
物件導向程式設計 (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; | |
| }; |
這裡 a 與 b 已經改放到 private 之後,也由於 a 與 b 都是 private 的,因此另外宣告 public 的 set_a() 與 set_b() 設定 a 與 b 之值, get_a() 與 get_b() 取得 a 與 b 之值。
存取標籤後面要接一個冒號,之後的成員依縮排方式加入。
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 |
重點整理
- 物件導向程式設計有封裝、繼承及多型等三大基本特性。
- 繼承像是親屬的重直關係(父母子女),多型則像是親屬的平行關係(兄弟姊妹)。
- 封裝連帶的觀念就是資訊隱藏,類別的成員變數只能在類別中處理,因此要把資料成員宣告在 private 存取標籤下。
- 外界要存取 private 的資料成員要透過 public 的存取函數與修改函數。
問題與討論
- 物件導向程式設計有哪三大基本特性?
- 什麼是封裝?為什麼要做封裝?
- 什麼是繼承?繼承機制有什麼優點?
- 什麼是多型?可以用什麼方式比擬嗎?
- 什麼是存取函數與修改函數?為什麼要有存取函數與修改函數?
練習
- 寫一個程式 exercise1101.cpp ,利用 exercise1005.cpp 設計的 IntegerDemo ,替 value 加入存取函數與修改函數。
- 寫一個程式 exercise1102.cpp ,利用 exercise1006.cpp 計算階層值的類別,替 value 加入存取函數與修改函數。
- 寫一個程式 exercise1103.cpp ,利用 exercise1007.cpp 計算費氏數列的類別,替 value 加入存取函數與修改函數。
the end
沒有留言:
張貼留言