<Effective C++>中的一個條款,如果是想要阻止一個對象的復制或是copy assignment操作應該怎麼做呢?
class HomeForSale {};
HomeForSale h1;
HomeForSale h2;
HomeForSale h3(h1); //企圖調用h3的copy構造函數克隆出一份h1
h1 = h2; //企圖調用copy assignment操作將h2對象完好的賦值給h1
以上兩個例子均是對一個對象的復制或是賦值,兩者說法不同,語法不同,調用時機不同,但是內部實現卻是差不多的。如題,我們要避免的就是以上這兩種例子的出現。
想要阻止這一類代碼的編譯不是很直觀的事情,通常來說,我們不想讓對象有某個操作,就不要聲明與實現相應的函數就是了,這對一般的函數來說確實是可以的,但是我們要阻止的兩個函數有一些特殊。這兩個函數即使我們不顯示的聲明與實現,只要我們的代碼在執行時有這兩個中的一個需求,編譯器都會為我們實現一份編譯器版本。如何是好呢?
答案是:編譯器為用戶自動生成的函數均為public函數,我們可以顯示的將這兩個函數聲明為private,又因為我們不會去調用他們,所以只是將他們生命為private,而不去實現他們。這麼做就達到了兩個目的:1顯示的聲明為private,編譯器得知用戶手動的聲明的函數,就不會再自作主張為我們創建編譯器版本了,也就不會有public相應函數了。2不實現,因為我們並不會去調用他們,所以實現了反而是畫蛇添足了。
類的成員函數或是類的友元函數都有權利去訪問類的私有域,但是這時候調用他們的話,會收到一個鏈接錯誤,因為我們並沒有實現出這兩個函數。我們能做的就是,盡可能的避免調用他們了。
這樣子一來,我們前面的那幾句代碼:
HomeForSale h1; //沒有可用的構造函數
HomeForSale h2; //同上
HomeForSale h3(h1); //企圖調用h3的copy構造函數克隆出一份h1,私有函數無法調用
h1 = h2; //企圖調用copy assignment操作將h2對象完好的賦值給h1,私有函數無法調用
將鏈接期錯誤轉到編譯器是可行的,就是設計基類。
class Uncopyable
{
protected:
Uncopyable() {}
~Uncopyable() {} //即使是基類也沒有將其析構函數設計為virtual,是這裡沒有動態釋放對象的需求。
private:
Uncopyable(const Uncopyable &c);
Uncopyable& operator= (const Uncopyable &c);
};
class HomeForSale:public Uncopyable
{
//這時候類中就不需求聲明copy構造函數,和copy assignment操作符了
};
這裡任何人,即使是成員函數或是友元函數嘗試拷貝HomeForSale,編譯器便試著生成一個copy構造函數或是copy assignment操作符,會去調用其基類的相應函數,因為基類中是private,所以編譯器生成失敗。拋出編譯器錯誤,及早的發現了問題。