1.copy建構函式與copy assignment操作符
copy 建構函式被用來「以同型物件初始化自我物件」,copy assignment操作符被用來「從另乙個同型物件中拷貝其值到自我物件」。
class widget
widget w1; //呼叫default建構函式
widget w2; //呼叫copy建構函式
w1 = w2; //呼叫copy assigment操作符
當你看到賦值符號時請小心,因為"="語法也可用來呼叫copy建構函式:
widget w3 = w2;
copy建構函式是乙個尤其重要的函式,因為它定義乙個物件如何passed by value,所以pass-by-value意味差「呼叫copy建構函式」。
2.explicit關鍵字
explicit只對建構函式起作用,用來阻止隱式轉換
class a
};void dosomething(a aobject); //函式,接受乙個型別為a的物件
a a(20);
dosomething(a); //正確
dosomething(20); //錯誤,使用explicit宣告了建構函式,無法進行隱式轉換
注意,explicit只對乙個引數的建構函式有效。也有一種例外情況,就是除第乙個引數外,其它引數均提供了預設引數。
3.若不想使用編譯器自動生成的函式,就該明確拒絕
編譯器可以暗自為class建立default建構函式、copy建構函式、copy assignment操作符,以及析函式。要阻止編譯的這樣的預設行為,可以將成員函式為private而且故意不實現它們:
class homeforsale ;
有了上述的class定義,當客戶企圖拷貝homeforsale物件,編譯器會阻撓他。哪果你不慎在member函式或者friend函式之內那麼做,輪到聯結器發出抱怨。我們可以定義乙個專門的base class,將連線期錯誤移至編譯期:
class uncopyable //允許derived物件構造和析構
~uncopyable() {}
private:
uncopyable(const uncopyable&); //但阻止copying
uncopyable& operator=(const uncopyable&);
}
為阻止homeforsale物件被拷貝,我們唯一需要做的是繼承uncopyable。當嘗試拷貝homeforsale物件,編譯器便試著生成乙個copy建構函式和乙個copy assignment操作符,這些函式的「編譯器生成版」會嘗試呼叫其base class的對應兄弟,那些呼叫會被編譯器拒絕,因為其base class的拷貝函式是private。boost中也提供了這樣的base class,名為noncopyable。
4.pure virtual析構函式
有時候希望擁有乙個抽象class,但是沒有任何pure virtual函式,怎麼辦?這時,可以宣告乙個pure vitual析構函式。下面是個例子:
class awov
注意乙個問題,你必須為這個pure virual析構函式提供乙份定義:
awov::~awov() //pure virtual析構函式的定義
編譯器會在awov的derived class的析構函式中建立乙個對~awov的呼叫動作,所以你必須為這個函式提供乙份定義。否則,聯結器會發出抱怨。
5.別讓異常逃離析構函式
析構函式中若丟擲異常,可能會導致資源沒有釋放完全。析構函式絕對不要吐出異常。如果乙個被析構函式呼叫的函式可能丟擲異常,析構函式應該捕捉任何異常,然後吞下它們(不傳播)或者結束程式。還有乙個解決辦法,提可能丟擲異常的操作放到乙個普通函式中,讓客戶有機會呼叫。
6.絕不在構造和析構過程中呼叫virtual函式
base class 構造期間呼叫的virtual函式,其實現呼叫的是base class中的版本,因為此時derived class根本還沒有進行構造,怎麼能呼叫其中的函式呢?所以物件在derived class建構函式開始執行前不會成為乙個derived class物件。相同道理也適用於析構函式。
7.在operator=中處理「自我賦值」
「自我賦值」發生在物件被賦值給自己時:
class widget ;
widget w;
...w = w; //賦值給自己
上面的情況很少發生,但有些**卻可能有潛在的自我賦值,例如:
a[i] = a[j]; //i和j可能相等
*px = *py;
假設你建立乙個class用來儲存乙個指標指向一塊動態分配的點陣圖:
class widget ;
下面是乙份不安全的operator=實現**:
widget& widget::operator=(const widget& rhs)
我們可以使用「證同測試」達到「自我賦值」的檢驗目的:
widget& widget::operator=(cosnt widget& rhs)
這樣做行得通,但是存在異常方面的麻煩,如果"new bitmap"導致異常,問題就出現了。其實還有一種辦法,我們只需要注意在複製pb所指東西之前別刪除pb:
widget& widget::operator=(cosnt widget& rhs)
省去了證同測試。
8.關於自定義的copy建構函式和copy assignment操作符
自定義derived class的copy建構函式和copy assigment操作符時,切記要呼叫base class的相應函式,否則將導致base class部分自製不完全。
摘自effective c++
ps :
C 構造 析構 賦值運算
有時候,某個物件是獨一無二的,不能沒複製也不能被賦值!所以我們要強制編譯器不允許使用 和copy 建構函式,但如果你不寫他們,編譯器又會自動幫你加上,問題由此引發。class home uncopyable private uncopyable const uncopyable uncopyable...
c 構造 析構 賦值 運算
1 為多型基類宣告virtual析構函式 帶有多型形態的base classs應該宣告乙個virtual析構函式。如果該class帶有任何virtual的函式,它就應該擁有乙個virtual析構函式。這樣用基類指標指向的派生類的析構的時候,才會呼叫到自己的析構函式,將派生類的所有部分都析構掉,否則只...
構造 析構 賦值運算
非內建資料型別 一般而言,只有當生出的 合法且有適當機會證明它有意義,編譯器才會為class 生出operator 建構函式 析構函式 stl 或標準庫或已經存在的,不包含虛函式的類,我們不應該繼承它們 比較好的一種辦法是,自己在析構函式中,可以選擇,記錄並退出,或者記錄並繼續執行。但同時提供乙個p...