1. 程式人生 > >構造/析構/賦值運算

構造/析構/賦值運算

per delete 被調用 拷貝 賦值操作符 fault virtual 主動 函數

一、C++默認編寫的函數

如果類中沒有定義,程序卻調用了,編譯器會產生一些函數:

  1. default 構造函數
  2. copy 構造函數
  3. copy assignment 操作符
  4. 析構函數(non virtual)

所以寫下:

class Empty { };

就好比寫下:

class Empty {
public:
    Empty(){ ... }
    Empty(const Empty& rhs) { ... }
    ~Empty() { ... }
    
    Empty& operator=(const Empty& rhs) { ... }
};
  • 這些函數都是public且inline。
  • 惟有當這些函數被需要(被調用),它們才會被編譯器創建出來。
  • 如果自己構造了構造函數(無論有無參數),編譯器不會產生default構造函數。
  • base class如果把拷貝構造函數或者賦值操作符設置為private,不會產生這兩個函數。
  • 含有引用成員變量或者const成員變量不產生賦值操作符。
  • 編譯器產生的析構函數是個non-virtual。

編譯器可以暗自為類創建default構造函數、copy構造函數、copy assignment操作符,以及析構函數。

二、拒絕編譯器自動生成函數

構造函數與析構函數是每一個類必須有的,但copy構造函數和copy assignment操作符對於某些類是不需要的需要明令禁止。
為了避免編譯器自動生成copy構造函數和copy assignment操作符可以將其聲明為private成員:

class Uncopyable{
private:
    Uncopyable(const Uncopyable&);
    Uncopyable& operator= (const Uncopyable&);
}

但類中成員函數和友元函數還是可以調用private函數,所以可以專門設計防止拷貝動作的基類(Boost也提供了這個類,名為noncopyable):

class nocopy : private Uncopyable {
...
}

派生類不再聲明copy構造函數和copy assignment操作符。
如果不需要copy構造函數和copy assignment操作符要明令禁止,為駁回編譯器自動(暗自)提供的機能,可將相應的成員函數聲明為private並且不予實現。使用像noncopyable這樣的基類也是一種做法。

三、為多態基類聲明virtual析構函數

  • 1.給多態基類應該主動聲明virtual析構函數
    如果多態基類析構函數沒有加聲明為virtual,當指向派生類對象的基類指針調用delete的時候,基類成分通常會被銷毀,而派生類的成分可能還留在堆裏。這可是形成資源泄漏、敗壞之數據結構、在調試器上消費許多時間。

  • 2.非多態基類,不要聲明virtual析構函數
    當類不企圖被當做基類的時候,不要令其析構函數為virtual。因為實現virtual函數,需要額外的開銷(指向虛函數表的指針vptr)。

多態基類一般包含一個virtual函數,所以一個類裏面有virtual函數則聲明virtual析構函數,沒有virtual則不聲明virtual析構函數。

構造/析構/賦值運算