類別 (class) 用來設計自己需要的物件 (object) ,這是說,類別是物件的藍圖。 C++ 中設計類別使用關鍵字 (keyword) class ,後面接大括弧宣告 (declare) 類別的成員 (member)
成員可以是資料 (data) 、函數 (function) 與建構函數 (constructor) ,資料其實就是專屬於類別的變數 (variable) ,我們在這裡沿用 C++ 的習慣稱之為資料成員 (data member) ,同樣的,函數也是專屬於類別的,稱之為成員函數 (member function) ,至於建構函數屬於特別的成員函數,用來建立該類別物件的專屬函數。
因為建構函數用來建立物件,所以建構函數沒有回傳值 (return value) ,或著可以這麼想像,建構函數預設回傳物件自己本身,因此無須宣告回傳值。
另外,類別定義必須利用存取標籤 (accsee label) public 或 private 將成員的權限歸類,屬於 public 的成員可以在程式中的任何地方存取, private 則只能在同個類別裡。
為什麼要對存取權限歸類呢?這是因為物件導向程式設計允許後續定義的類別繼承 (inherit) 之前定義類別的特性,這樣的機制使 public 成員會被繼承,而 private 不能被繼承。還有另一個存取標籤 protected ,不過這不在我們目前的討論範圍。
我們舉一例如下
001 | #include <iostream> |
002 | |
003 | using namespace std; |
004 | |
005 | // 宣告類別 |
006 | class Demo { |
007 | // 宣告 public 成員 |
008 | public: |
009 | int a; |
010 | int b; |
011 | int DoSomething(); |
012 | }; |
013 | |
014 | // 實作 Demo 的 DoSomething() 成員函數 |
015 | int Demo::DoSomething() { |
016 | return a + b; |
017 | } |
018 | |
019 | // 程式執行的 main() |
020 | int main(void) { |
021 | // 宣告並建立 Demo 型態的物件 t |
022 | Demo t; |
023 | t.a = 11; // 直接設定成員變數值 |
024 | t.b = 22; |
025 | |
026 | cout << endl; |
027 | // 呼叫並印出 DoSomething() 的回傳值 |
028 | cout << t.DoSomething() << endl; |
029 | cout << endl; |
030 | |
031 | return 0; |
032 | } |
033 | |
034 | /* 檔名: class_demo.cpp |
035 | 作者: Kaiching Chang |
036 | 時間: 2014-5 */ |
此例中的 Demo 類別宣告三個 public 成員, a 、 b 為成員變數, DoSomething() 為成員函數,記得, class 大括弧的最後要加上分號
005 | // 宣告類別 |
006 | class Demo { |
007 | // 宣告 public 成員 |
008 | public: |
009 | int a; |
010 | int b; |
011 | int DoSomething(); |
012 | }; |
底下為實作 Demo 類別中的 DoSomething() 成員函數
014 | // 實作 Demo 的 DoSomething() 成員函數 |
015 | int Demo::DoSomething() { |
016 | return a + b; |
017 | } |
DoSomething() 的工作很簡單,就是回傳兩個成員變數 a 與 b 的相加值。這裡須注意定義成員函數時,必須在成員函數名稱前加上所屬類別名稱接兩個冒號
015 | int Demo::DoSomething() { |
這是標明 DoSomething() 是屬於 Demo 類別的,連續兩個冒號 :: 為作用域運算子 (scope operator) 。沒有這樣寫的話,編譯器 (compiler) 會把 DoSomething() 當成普通的函數處理。
也可以直接把成員函數的實作直接寫在宣告的地方,我們建議分開寫,因為小程式可能看起來沒差,大型程式在習慣上會把宣告放在標頭檔 (header file) 。
下面的 main() 直接用小數點運算子設定 a 與 b ,然後印出 DoSomething() 的回傳值
019 | // 程式執行的 main() |
020 | int main(void) { |
021 | // 宣告並建立 Demo 型態的物件 t |
022 | Demo t; |
023 | t.a = 11; // 直接設定成員變數值 |
024 | t.b = 22; |
025 | |
026 | cout << endl; |
027 | // 呼叫並印出 DoSomething() 的回傳值 |
028 | cout << t.DoSomething() << endl; |
029 | cout << endl; |
030 | |
031 | return 0; |
032 | } |
編譯執行看看結果吧
這個例子我們只用到 public ,接下來我們要繼續介紹 private ,將資料有效的封裝 (encapsulation) 在物件裡。
中英文術語對照
類別 | class |
物件 | object |
關鍵字 | keyword |
宣告 | declare |
成員 | member |
資料 | data |
函數 | function |
建構函數 | constructor |
變數 | variable |
資料成員 | data member |
成員函數 | member function |
回傳值 | return value |
存取標籤 | accsee label |
繼承 | inherit |
作用域運算子 | scope operator |
標頭檔 | header file |
編譯器 | compiler |
封裝 | encapsulation |
重點整理
- 類別是物件的藍圖,每一個類別都可以定義資料成員及成員函數,宣告類別使用關鍵字 class ,每個成員都要用存取標籤分類,大括弧的最後要加上分號。
- 建構函數屬於特別的成員函數,用來建立該類別的物件。
- 成員函數的實作通常會放在類別宣告外,需要標上類別名稱與作用域運算子表示屬於哪個類別。
- 宣告建立類別的物件(變數)後,可用小數點運算子指派數值給 public 的成員變數,也可用小數點運算子呼叫成員函數。
問題與討論
- 為什麼類別要有專屬的變數及函數?想一想,這跟物件的意涵有什麼關聯?
- 成員函數跟一般的函數有什麼不同?資料成員跟一般的變數又有什麼不同?
- 除了建構函數、成員函數及資料成員之外,類別中還有其他種類的成員嗎?
- 為什麼要有建構函數?建構函數的用途是什麼?
- 為什麼成員函數的實作要放在類別宣告之外?
練習
- 寫一個程式 exercise1001.cpp ,裡頭設計一個類別 IntegerDemo , IntegerDemo 有一個 int 的成員變數 value ,另有一個沒有回傳值的成員函數 add() , add() 有一個 int 參數,呼叫 add() 時會把參數與 value 相加,結果儲存在 value ,執行部分先將 value 設定為 25 ,再呼叫 add() 以 24 當參數。
- 承上題,另寫一個程式 exercise1002.cpp ,改成由使用者輸入兩個整數。
- 承上題,另寫一個程式 exercise1003.cpp ,加入成員函數 subtract() , subtract() 沒有回傳值另外需要一個 int 參數,同樣呼叫 subtract() 是將 value 減去參數值,最後結果儲存在 value 。
- 承上題,另寫一個程式 exercise1004.cpp ,繼續擴充 IntegerDemo ,加入乘法的成員函數。
- 承上題,另寫一個程式 exercise1005.cpp ,繼續擴充 IntegerDemo ,加入除法的成員函數。
- 寫一個程式 exercise1006.cpp ,仿照 IntegerDemo ,將成員函數改成計算階層值,結果儲存在 value 。
- 寫一個程式 exercise1007.cpp ,仿照 IntegerDemo ,將成員函數改成計算費氏數列,結果儲存在 value 。
the end
沒有留言:
張貼留言