1. 程式人生 > >c++程式設計習慣五(若不想使用編譯器自動生成的函式,就直接拒絕)

c++程式設計習慣五(若不想使用編譯器自動生成的函式,就直接拒絕)

在實際情況下,我們的class並不總是應該有copy建構函式和賦值操作符,如果當別人不小心呼叫了它,編譯器又會為我們自動生成,這樣就出現了一個尷尬的情況。

下面來舉個實際的例子:一個地產中級商賣房子,在中介軟體系統中想必有一個class用來描述房屋:

 class Home{...};

那麼Home物件是一筆資產,它是獨一無二的,為Home物件做一份副本似乎沒什麼道理。怎麼能去複製對於無二的東西呢,所以:

Home h1;
Home h2;
Home h3(h1); //企圖拷貝h1;
h1=h2; //企圖拷貝h2

我們知道這兩種行為都不應該通過編譯,他們分別呼叫了copy建構函式和賦值操作符。

阻止這一類程式碼的編譯,如果是平常的操作,我們只要不宣告對應的函式就好了,這個策略對copy和賦值似乎不起作用,你不宣告他們,當有人嘗試呼叫它們時,編譯器會為你宣告它們。

似乎我們被弄的很尷尬,如果不宣告,編譯器會產出一份,於是我們宣告,但是class還是支援copying。但是我們的目標是阻止copying。

那我們應該怎麼做呢?

所有編譯器生成的函式都是public,為了阻止這些函式被建立,我們只能自行宣告它們,這就為我們提供了思路,我們可以將copy建構函式或賦值操作符宣告為private。這樣就阻止了編譯器暗自建立專屬版本;然後把這些函式私有,使得你可以成功阻止人們呼叫。

一般來說,這個做法也不是一定安全的,因為成員函式和友元函式還是可以呼叫他們。那麼我們就可以這樣做啦,支取宣告,卻不去定義,這樣在被呼叫時,就會出現連線錯誤。這一伎倆是被大家所接受的,c++的iostream程式庫中阻止copying行為。

我們回到例子:

class Home{
public:
    ...
private:
    Home(const Home& );//只有宣告
    Home& operator=(const Home &);

這裡不寫函式引數,就更加能體現,這個函式不用實現,它只是一個宣告。

這樣就可以了。客戶企圖拷貝時,編譯器就會阻撓它,如果在friend和member函式之內這麼做,輪到聯結器阻撓。

到這裡你以為就完了嗎?我們可不可以把連線期的錯誤移至編譯期呢,答案是可以的:只要將copy建構函式和賦值操作符宣告為private就可以辦到,但是不是在Home自身內,而是在一個專門為了阻止copying動作而設計的基類內。這個基類非常簡單:

class Uncopy{
protected:        //允許派生類物件構造和析構
    Uncopy(){}
    ~Uncopy(){}

private:
   Uncopy(const Uncopy& );//阻止拷貝
   Uncopy& operator=(const Uncopy&);
};
//然後繼承
class Home:private Uncopy
{
...
}
//不需要再宣告建構函式或賦值操作符了

因為這時候,只要任何想要呼叫copying的操作,編譯器都會試著生成,然後就會去呼叫基類中的兄弟,這樣就會被編譯器拒絕,是不是很巧妙。

總結:為了拒絕編譯器自動生成的函式,可將相應的成員函式宣告為private並且不予以實現。或者在基類中實現也是一種好的方法!