C++ 入門指南

單元 11 - 物件導向與封裝

本書已有新版,請參考 C++ 入門指南 4.01 - 單元 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;
}

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

#include <iostream>

using namespace std;

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;
};

int Demo::DoSomething() {
    // 改成呼叫 getter 成員函數
    return 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;
}

int main(void) {
    Demo t;
    // 由呼叫 setter 設定成員變數
    t.set_a(12);
    t.set_b(23);
    
    cout << endl << t.DoSomething() << endl << endl;
    
    return 0;
}

/* 《程式語言教學誌》的範例程式
   http://kaiching.org/
   檔名:class_demo2.cpp
   功能:示範定義類別
   作者:張凱慶 */

編譯執行結果如下

-classdemo2-

但是這樣設定成員變數還得額外呼叫 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 加入存取函數與修改函數。

上一頁 單元 10 - 類別
回 C++ 入門指南首頁
下一頁 單元 12 - 建構函數
回 C++ 教材
回程式語言教材首頁