c 筆記 構造 析構 賦值運算

2021-06-05 16:06:07 字數 2979 閱讀 3559

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...