C++ 入門指南 V2.00 - 單元 11 - 物件導向與封裝




物件導向程式設計 (object-oriented programming) 有三大基本特性,分別是封裝 (encapsulation) 、繼承 (inheritance) 及多型 (polymorphism)



繼承的目的是讓類別 (class) 具有像是親屬的垂直關係(父母子女),子類別 (subclass) 可以擁有父類別 (superclass) 的成員 (member) ,而多型像是親屬的平行關係(兄弟姊妹),多個子類別繼承自單一父類別之時,這些子類別就可以用父類別代替,父類別如同家族裡的「姓」,子類別則是「名」。


繼承的英文原文 inherit ,中文意思泛指從什麼得到什麼,生物學上的遺傳也是用這個詞。

至於封裝的意思就是把資料 (data) 封在類別中,這還牽涉到程式設計中另一個重要的概念             資訊隱藏 (information hiding) ,主要就是不讓外界隨意存取類別的資料,也就是說,只讓類別的資料成員 (data member) 給同個類別的成員函數 (member function) 存取。


這就要用到 private 存取標籤 (access label) 了,就是把成員變數放在 private 之後,而其他可供外界存取的成員函數放在 public 之後


    class Demo {
    // 宣告 public 的成員
    public:
       void set_a(int n);
       void set_b(int n);
       int get_a();
       int get_b();
       int DoSomething();
   
    // 宣告 private 的成員
    private:
       int a;
       int b;
    };

這裡 ab 已經改放到 private 之後,也由於 ab 都是 private 的,因此另外宣告 publicset_a()set_b() 設定 ab 之值, get_a()get_b() 取得 ab 之值。


存取標籤後面要接一個冒號,之後的成員依縮排方式加入。

set_a()set_b() 為修改函數 (mutator) ,就是俗稱的 setter ,至於 get_a()get_b() 為存取函數 (accessor) ,也就是是俗稱的 getter

因此 set_a()set_b()get_a()get_b() 的實作很簡單,如下


    // setter 與 getter 成員函數
    void Demo::set_a(int n) {
       a = n;
    }
   
    void Demo::set_b(int n) {
       b = n;
    }
   
    int Demo::get_a() {
       return a;
    }
   
    int Demo::get_b() {
       return b;
    }

我們寫成一個完整範例,如下


001 #include <iostream>
002
003 using namespace std;
004
005 class Demo {
006 // 宣告 public 的成員
007 public:
008    void set_a(int n);
009    void set_b(int n);
010    int get_a();
011    int get_b();
012    int DoSomething();
013
014 // 宣告 private 的成員
015 private:
016    int a;
017    int b;
018 };
019
020 int Demo::DoSomething() {
021    // 改成呼叫 getter 成員函數
022    return get_a() + get_b();
023 }
024
025 // setter 與 getter 成員函數
026 void Demo::set_a(int n) {
027    a = n;
028 }
029
030 void Demo::set_b(int n) {
031    b = n;
032 }
033
034 int Demo::get_a() {
035    return a;
036 }
037
038 int Demo::get_b() {
039    return b;
040 }
041
042 int main(void) {
043    Demo t;
044    // 由呼叫 setter 設定成員變數
045    t.set_a(11);
046    t.set_b(22);
047
048    cout << endl;
049    cout << t.DoSomething() << endl;
050    cout << endl;
051
052    return 0;
053 }
054
055 /* 檔名: class_demo2.cpp
056    作者: Kaiching Chang
057    時間: 2014-5 */

編譯執行結果如下



但是這樣設定成員變數還得額外呼叫 set_a()set_b() ,有點麻煩,我們希望宣告 (declare) 時就能夠直接設定,嗯,這用建構函數 (constructor) 就可以囉!


中英文術語對照


物件導向程式設計 object-oriented programming
封裝 encapsulation
繼承 inheritance
多型 polymorphism
類別 class
子類別 subclass
父類別 superclass
成員 member
資料 data
資訊隱藏 information hiding
資料成員 data member
成員函數 member function
存取標籤 access label
修改函數 mutator
存取函數 accessor
宣告 declare
建構函數 constructor

重點整理


  1. 物件導向程式設計有封裝、繼承及多型等三大基本特性。
  2. 繼承像是親屬的重直關係(父母子女),多型則像是親屬的平行關係(兄弟姊妹)。
  3. 封裝連帶的觀念就是資訊隱藏,類別的成員變數只能在類別中處理,因此要把資料成員宣告在 private 存取標籤下。
  4. 外界要存取 private 的資料成員要透過 public 的存取函數與修改函數。

問題與討論


  1. 物件導向程式設計有哪三大基本特性?
  2. 什麼是封裝?為什麼要做封裝?
  3. 什麼是繼承?繼承機制有什麼優點?
  4. 什麼是多型?可以用什麼方式比擬嗎?
  5. 什麼是存取函數與修改函數?為什麼要有存取函數與修改函數?

練習


  1. 寫一個程式 exercise1101.cpp ,利用 exercise1005.cpp 設計的 IntegerDemo ,替 value 加入存取函數與修改函數。
  2. 寫一個程式 exercise1102.cpp ,利用 exercise1006.cpp 計算階層值的類別,替 value 加入存取函數與修改函數。
  3. 寫一個程式 exercise1103.cpp ,利用 exercise1007.cpp 計算費氏數列的類別,替 value 加入存取函數與修改函數。

the end

沒有留言: