Effective C++讀書筆記(二)

二、構造/析構/賦值運算


條款05:瞭解C++默默編寫並調用哪些函數

如果你自己沒聲明,編譯器就會爲它聲明(編譯器版本的)一個copy構造函數,一個copy assignment操作符和一個析構函數。此外如果你沒有聲明任何構造函數,編譯器也會成爲你聲明一個默認構造函數。所有這些函數都是publicinline

惟有當這些函數被需要(被調用),它們纔會被編譯器創建出來

注意:編譯器產生的析構函數是個non-virtual,除非這個classbase class自身聲明有virtual析構函數。

如果一個類的成員變量是reference,因爲c++並不允許讓reference改指向不同對象,所以c++的響應是拒絕編譯那一行賦值動作。你可以自己定義copy assignment操作符。

如果成員變量是const,則更不合法,編譯器不知道如何在它自己生成的賦值函數內面對它們。

最後一種情況:如果某個base classescopy assignment操作符聲明爲private,編譯器拒絕爲其derived classes生成一個copy assignment操作符。畢竟編譯器爲derived classes所生的copy assignment操作符想象中可以處理base class成分,但它們當然無法調用derived class無權調用的成員函數。

 請記住:

  • 編譯器可以暗自爲類創建默認構造函數、拷貝構造函數、拷貝賦值操作符,以及析構函數。   

條款06:若不想使用編譯器自動生成的函數,就該明確拒絕

只要將copy構造函數和copy assignment操作符聲明爲private就可以生成一個專門爲了阻止copying動作而設計的base class。這個base class非常簡單:

class Uncopyable

{

 

protected

      Uncopyable(){}                          

      ~Uncopyable(){}                        //允許derived對象構造和析構

private

      Uncopyable(constUncopyable&);//但阻止copying

      Uncopyable&operator=(const Uncopyable&);

};

爲了阻止一個類對象被拷貝,我們唯一需要做的就是繼承Uncopyable;

Uncopyable class的實現和運用非常微妙,包括不一定得以public繼承它,以及Uncopyable的析構函數不一定得是virtual等等。

請記住:

  • 爲駁回編譯器自動(暗自)提供的機能,可將相應的成員函數聲明爲private並且不予實現。使用像noncopyable這樣的基類也是一種做法。   

條款07:爲多態基類聲明virtual析構函數

      derived class對象經由一個base class指針被刪除,而該base class帶着一個non-virtual析構函數,其結果未有定義----實際執行時通常發生的是對象的derived成分沒被銷燬。消除這個問題的做法很簡單:給base class一個virtual析構函數。此後刪除derived class對象就會銷燬整個對象。

任何class只要帶有virtual函數都幾乎確定應該也有一個virtual析構函數。

如果一個class不含virtual函數,通常表示它並不意圖被用做一個base class,當class不企圖被當做base class的時候,令其析構函數爲virtual往往是個餿主意。因爲實現virtual函數,需要額外的開銷(指向虛函數表的指針vptr)。

不能企圖繼承一個標準容器或任何其他帶有non-virtual析構函數的class(很不幸c++沒有提供類似javafinal classesc#sealed classes那樣的禁止派生機制)

如果pure virtual函數導致abstract class,也就是不能被實體化的class。由於抽象class總是企圖被當做一個base class來用,而又由於base class應該有個virtual析構函數,並且由於pure virtual函數會導致抽象class,因此解法很簡單:爲你希望它成爲抽象的那個class聲明一個pure virtual析構函數。但是你必須爲這個pure virtual析構函數提供一份定義。析構函數的運作方式是,最深層派生的那個class其析構函數最先被調用,然後是其每一個base class的析構函數被調用。如果不給一份定義,連接器會發出抱怨。

 請記住:

  • 帶有多態性質的基類應該聲明一個virtual析構函數。如果一個類帶有任何virtual函數,它就應該擁有一個virtual析構函數。
  • 一個類的設計目的不是作爲基類使用,或不是爲了具備多態性,就不該聲明virtual析構函數。   
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章