1. Object Based(基於對象) vs. Object Oriented(面向對象)
Object Based: 面對的是單一class的設計;
Object Oriented:面對的是多重classes的設計,class 和 class 之間的關系。
classes 的兩個經典分類:
- class without pointer members -- complex
- class with pointer members -- string
2. Header (頭文件)
2.1 防衛式聲明
2.2 把 complex 的實部和虛部寫成模板類
2.3 inline
inline 關鍵字是對編譯器的建議。建議把某個函數定義為內聯函數。實際上,是否定義為內聯函數,由編譯器決定。
定義在類內的函數,都是 “提議” 為內聯函數。
2.4 訪問級別
所有數據成員都應該是private;
供外部使用的函數成員都應該是public,只供類內使用的函數成員可以是private;
2.5 構造函數
complex (double r = 0, double i = 0) : re (r), im (i) // initialization list(初值列,初始值) {}
complex (double r = 0, double i = 0) { re = r; im = i; }
上述是 2 種形式的構造函數,其結果都是對 re 和 im 進行賦值。但是,使用 initialization list 的代碼效率更高,更彰顯編程素養。
2.6 不需要析構函數
complex 類沒有指針成員,因此不必使用析構函數。
2.7 構造函數可以有很多個 -- overloading
下圖所示,由於構造函數 (1) 的形參全部具有默認值,所以重載函數 (2) 會造成調用混亂。
而 real() 函數,編譯器根據其返回值類型,形參類型和數量,定義了一個獨一無二的函數名稱(右下角所示)。
2.8 構造函數為private權限
構造函數為private,即不允許外界創建對象。
舉例子,一個設計模式,singleton,只允許該類創建一個對象。通過類內的靜態函數創建對象。
2.9 const member functions(常量成員函數)
若 real() 和 imag() 函數都沒有加 const 關鍵字,如下面2種使用方式,左邊是成立的,右邊卻不成立。原因在於,c1 是個 const 變量,若其調用 real(), real() 告訴編譯器可以修改 c1 的值,出現矛盾,報錯。
2.10 返回值傳遞: return by value vs. return by reference( to const )
返回值優先考慮傳引用。
什么情況下可以返回引用?
若返回的變量A是在函數內創建,函數結束后,棧內存釋放,變量A銷毀。此時便不可以返回A的引用。
2.11 參數傳遞: by value vs. by reference( to const )
2.12 friend 友元
complex 類認可 _doapl() 是它的友元函數,則在該函數內部可直接訪問 complex 類的 private 數據成員。
相同 class 的各個 objects 互為友元,因此如下函數成立。
2.13 操作符重載 -- 類內成員函數
在 complex 類內重載 += 運算符。其中,c1 作為重載運算符實參,對應的形參為 const 的引用類型。this 指針是類內成員函數的隱藏形參,此時 this 指針指向重載運算符的調用者,即 c2 .
關於返回值的語法分析
重要概念:傳遞者無需知道接收者是以 reference 形式接收。
如下,舉兩個例子:
- 函數 _doapl() ,返回值為 complex&,是接收者;函數內 return *this; ,*this 作為傳遞者, 並非引用類型。
- 符號重載函數 += 的調用方式為 c2 += c1; 。實參 c1 為傳遞者,傳值;形參 const complex & r 作為接收者,是引用類型。
對於 c2 += c1; ,符號重載函數的返回值可以為 void;
對於 c3 += c2 += c1; ,符號重載函數的返回值必須為 complex&。此時,c1 先加 c2,返回 complex & 類型的右值。之后調用該右值的符號重載函數,與 c3 相加。
2.14 符號重載函數 -- 全局函數
操作符 << 的重載,只能定義為全局函數。原因如下,
cout << conj(c1); ,操作符 << 只能作用在左邊的 cout 上。cout 是輸出流對象,無法在其類定義中添加操作符 << 的重載函數。因此,只能將操作符 << 重載函數定義為全局函數。
操作符 << 重載函數的實現:
- cout 是 ostream 類型的對象;
- 形參優先使用傳引用;
- 形參不能使用 const,因為往 os 中傳值,會改變 os 的狀態;
- cout << conj(c1); ,返回類型可以為 void;
- cout << c1 << conj(c1); ,返回類型必須為 ostream,且優先考慮返回引用。該語句的調用順序為, cout << c1,返回 ostream 類型的右值。調用該右值的 << 重載函數輸出 conj(c1).
注意事項總結:
- 構造函數使用 initialization list;
- 函數是否定義為const;
- 函數參數盡量使用&,const;
- 函數返回值盡量使用&,const;
- 數據成員為private;