如果你只是聲明一個空類,不做任何事情的話,編譯器會自動為你生成一個默認構造函數、一個拷貝默認構造函數、一個默認拷貝賦值操作符和一個默認析構函數。這些函數只有在第一次被調用時,才會別編譯器創建。所有這些函數都是inline和public的。
默認的析構函數是非虛函數(除非基類有自己聲明的虛析構函數)。而拷貝默認構造函數和默認拷貝賦值操作符知識是單純將來源對象的每一個非靜態成員拷貝到對象目標中(bitwise copy)。
其中的默認拷貝賦值操作符只有在生成的代碼合法并且有機會證明它有意義存在時才會生成。這就說明,如果你打算在一個“內含引用成員”或者“內含const成員”的類內支持賦值操作,就必須定義自己的默認拷貝賦值操作符。因為C++本身不允許引用改指不同的對象,也不允許更改const成員。
最后一種情況,當基類將自己的默認拷貝賦值操作符聲明為private時,子類就不會產生自己的的默認拷貝賦值操作符。因為假如產生了這樣的默認拷貝賦值操作符,它會試著去調用基類的默認拷貝賦值操作符去處理基類的部分,不幸的是,它沒有權利。
你可以將拷貝構造函數或默認拷貝賦值操作符聲明為private。這樣明確聲明一個成員函數,就阻止了編譯器暗自創建的默認版本,而這些函數為private,使得可以成功阻止人們調用它。
上面的做法有一個隱患,因為類自身的member和friend還是可以調用這些private函數。有一個很刁鉆的方法,“將成員函數聲明為private而且故意不實現它們”,這樣既阻止了默認函數的生成,而且如果你試著調用這些函數,就會得到一個鏈接錯誤。只聲明,不定義,鏈接器報錯。甚至在聲明的時候,你連參數也不用寫。
而試著將上述的鏈接器錯誤提前到編譯器也是可以的。我們專門設計一個類Unconpyable。
--------------------------------------------------------------------
class Uncopybale {
protected:
??? Uncopyable() {}
??? ~Uncopyable() {}
private:
??? Ucopyable(const Uncopyable&)
??? Uncopyable& operator=(const Uncopyable&)
};
--------------------------------------------------------------------
為了阻止對象被拷貝,我們唯一需要做的就是繼承Uncopyable。這些函數的默認生成版本會嘗試調用其基類的對應版本,那些調用會被編譯器拒絕,因為它基類的拷貝函數是private。
Boost提供的noncopyable類也有類似的功能。
忠告:
為了駁回編譯器自動提供的技能,可將相應的成員函數聲明為private并且不予實現。使用像Uncopyable這樣的基類也是一種做法。