一個 物件 是由 一些 資料 與作用 其上 的 函數 或稱方法(method)。 一個 類別 可說成是 一種物件的 描述。
類別 (clas s) 的設定,可以分成兩部分, 一部分是 資料儲存部分,稱之為 資料成員(data members),另一部分是 作用於這些資料 的相關 函數,稱之為 成員函數 (member *s)。
按資料成員 與 成員函數使用方式, 可分為自用 (private) 部分,與 公用 (public) 部分。
公用部分 亦可稱為 使用介面。
沒有成員函數 的類別, 其架構如同 struct 的架構,其使用方式 (即一個 物件的定義) 也相同。一個沒有成員函數 的類別的宣告, 其格式如下:
clas s clas sName
{
public:
dataType1 a;
dataType2 b;
...
private:
dataType3 c;
dataType4 d;
...
};
說明:
a 與 b, 為公用資料成員 (data member) 或變數, (將 a 與 b 說是變數 是不正確的, 其不具有記憶体空間。) 公用變數於程式各處均可引用。
c 與 d, 為私用變數, 僅有 該 clas s 的成員函數中可以引用該變數。
clas sName 如同 一個使用者自定的 struct 資料型態, 其變數的 定義方式如同 一般的變數的定義一般, 即 clas sName obj ectName;。 此時, 變數 obj ectName 已不稱為變數, 而稱為 物件。
例: 類別 CTest 的宣告 與 物件 obj ect 的定義。
#include<iostream>
c lass CTest // 類別 CTest 的宣告
{
public:
int x, y;
private:
int a, b;
};
main()
{
CTest obj ect; // 物件 obj ect 的定義
obje ct.x = 2; // 資料成員 x 的引用
obje ct.y = 3; // 資料成員 y 的引用
// obj ect.a = 4; // compile error
cout << "x = " << obj ect.x << "; y = " << obj ect.y << endl;
}
欲達到 資料的一致性, 資料的隱藏是一個可行的辦法。
一個類別的成員函數, 亦可分成 自用 與 公用 的 使用方式,公用部分 亦可稱為 使用介面。 使用者僅知道 使用介面 就可以 使用 該類別,可以 省去 對使用介面 的 詳細 內容。
例如, 於第 11 章所提的堆疊 (stack) 的類別 CStack, 我們只要知道其 public 函數的作用, 如 isEmpty()、 isFull()、 push(char c) 及 pop(),就可直接使用它們,如例 3。
例: clas s CStack 與 obj ect stack
clas s CStack
{
public:
int isEmpty( );
int isFull( );
void push(char c);
char pop( );
...
}
main()
{
CStack stack;
char c;
...
if(!stack.isFull())
stack.push(c);
...
if(!stack.isEmpty())
c = stack.pop();
}
一般而言, 一個 clas s 的宣告, 可以將之分成兩個 檔案, 一個是 .h 檔, 另一個是 .cpp 檔。
.h 檔含 clas s 資料成員的宣告 及 成員函數的標題(即,宣告), 但不含成員函數的定義(即,函數主体)。 cpp 檔 才含成員函數的主體。
物件導向:
簡單的說,一個人是由頭、手、腳及各個器官所組成。
人是一個物件,人會做愛,而做愛是一種懷孕的(方法)。
物件也會有屬性,物件1叫Tom、物件2叫Mary。
叫Tom(屬性)的人(物件)做愛(方法)和叫Mary(屬性)的人(物件),導致懷孕(結果)。
人這個物件是可以重覆使用,給予不同的屬性。
物件導向是為了模擬真實世界的具體或抽象的事物,並可重覆利用。
物件導向的特性:
1. 抽象化 (Abstraction)
clas s 的使用就具有這種功能, 就是將 作用在 資料(成員) 的 (成員)函數 與 資料(成員) 結合在一起,並限定 其 使用權限以達成 資料使用 的 一致性, 如此一來 就 可達到資料的抽象化。 資料的抽象化 的好處 是 對於一個 clas s 就知道如何 去使用它, 省去對其 內部詳細 架構的了解, 就像 一個函數 sqrt() 就代表一串的 程式碼, 亦是一種 抽象化, 我們 可以 省去對其 程式碼 的了解 就可直接 使用該函數。
2. 封裝 (Encapsulation)
打遊戲機時,我們不需要了解,遊戲機的構造,只需要了解如何將遊戲光碟載入啟動遊戲。
如果隨意的拆開遊戲機,將裡面的線路改變亂插,就會導致整台機器無法再使用。
3. 繼承 (Inheritance)
你會遺傳到你老爸的基因,例如:捲毛、膚色。但是你可能會因外在因素產生一些新的特徵,是你老爸沒有的。但基本上兒子大多數的特徵還是來自於老爸。
父類別一部基本的汽車,有方向盤、四個輪子、引擎...等等。
子類別可能是賽車 繼承 了父類別基本的汽車構造,但是他可能另外有渦輪噴射;消防車可以噴水;早餐車可以做早餐;箱型車可以搞車震,子類別繼承了父類的屬性和方法,還可以另外加上自己獨特的方法。
4. 多型 (Polymorphism)
同樣是電視,媽媽看韓劇,爸爸看新聞,弟弟看A片,如果電視是方法,就會因不同的人(參數),產生不同的結果。
5. 動態連結 (Dynamic binding)
一般呼叫物件方法有兩種方式:靜態(Static)連結與動態(Dynamic)連結。
靜態連結:
編譯器在程式編譯階段就將物件與方法連結在一起。
例 :
you.Fuck()直接編譯成機器碼直接呼叫you物件的Fuck()方法。
動態連結:
在程式編譯階段不將物件與方法連結在一起,而將物件的方法位置建立成一個虛擬表格。
執行時才判斷應呼叫哪個物件的方法函式,因此可做到物件多型。
不同程式語言或不同編譯器內部處理的方式都不太一樣,但並不影響程式的設計,因為都由編譯器自己處理了。
-----------------------------------------------------------------
請練習寫出一個類別包含一個物件與方法。