如何專業的定義一個class?這裡記錄一下自己的checklist
- 關於構造函數的注意點
a. 構造函數聲明為explicit,避免隱式轉換
b. 考慮禁用復制構造函數、賦值函數
c++中,默認對於類會產生以下成員函數(如果你沒有定義的話,這通常是不可控的)
class Empty() { public: Empty(); ~Emtpy(); Empty* operator&(); //取址運算符 const Empty* operator&() const; //取址運算符 const private: Empty(const Empty &); //賦值構造函數 Empty& operator=(const Empty &); //賦值運算符 }
這裡取址函數不用多說,關鍵是賦值相關的兩個函數,默認是淺copy的,所以還是禁用,參考析構函數注意點
c. 構造函數盡管可以拋出異常,但沒有返回值;所以可以考慮單獨實現一個Init函數作為補充
- 采用初始化列表而不是賦值初始化成員變量,有兩種情況你必須這樣做:
a. const \ reference的成員
b.派生類的方法中需要調用基類的構造函數
Base(int x):m_x(x) { } Derived(int x) : Base(x) { }
- 成員函數如果不改變類的狀態,聲明時後加const
- 盡可能將成員變量private更可控,更透明
- 以非member 方法代替需要多個對象的member組合功能的實現
- 考慮Law of Demeter,適當做一個權衡,少一些wrapper或中介類
- 關於析構函數的注意點
a. 一個類要被繼承時(其往往含有虛函數要多態),要提供虛析構函數,否則存在下面的情況:
Base *pb = new Derived(); delete pb;//這裡就不會調用派生類的析構函數,盡管pb的虛指針指向了派生的虛表,但其虛表中沒有虛析構函數,造成派生對象資源洩露
b.只要有基類的析構函數是虛擬的,那麼所有的派生類不管是否明確的寫了虛擬析構函數,派生了的析構函數可以認為一定是虛擬的。如同類的虛指針,所有派生的默認都有
c.在析構中不要拋出exception,否則實現此異常接口
如果類含有指針成員和引用成員,則該類型通常需要實現析構函數(這裡不一定是虛的,但是需要考慮清理內存)
更進一步,一旦實現了析構函數,就進而需要實現實現拷貝構造函數與拷貝復制函數,否則,需要明確拒絕(或者,僅僅一個理由:做副本有沒有道理,見這裡第一個條款)