C Primer 學習筆記 複製控制

2021-06-19 01:27:07 字數 3751 閱讀 6695

複製建構函式、賦值操作符和析構函式總稱為複製控制。

一.複製建構函式

1.複製建構函式用途

只有單個形參,而且該形參是對本類型別物件的引用(通常是const修飾)的建構函式,稱為複製建構函式,它通常可用於:

1.根據另乙個同型別的物件顯示或隱式初始化乙個物件. 

string  str1 = "100000";

string str2("9999");

string str3(str2);

區別在於第一種形式先呼叫乙個接受c風格字串的string建構函式,建立乙個臨時物件,然後呼叫string複製建構函式將str1初始化為臨時物件的副本;第二種則是呼叫建構函式在生成物件str2的同時即刻進行了初始化"9999"。效率上來說當然後者更高,也是我們提倡的初始化方式。第三種則顯式呼叫了複製建構函式將str2複製給str3 。

2.複製乙個物件,將它作為實參傳給乙個函式 

3.從函式返回時複製乙個物件

當形參為非引用型別時,將複製實參的值;以非引用型別作為返回值時,將返回return語句中值的副本。

當函式的形參或者返回值為類型別時,由複製建構函式進行複製。如:

//複製建構函式用於複製返回值,而這裡的引數為引用,不會呼叫複製建構函式

string make_plural(size_t, const string&, const string&);

4.初始化順序容器

//預設string建構函式和5個string複製建構函式被呼叫

vectorsevc(5);

先呼叫string預設建構函式建立乙個臨時值來初始化svec,然後使用複製建構函式將臨時值複製到sevc的每個元素

5.根據元素初始化式列表初始化陣列元素

sales_item primer_eds = ;
2.合成複製建構函式如果我們沒有定義複製建構函式,編譯器就會為我們合成乙個。與合成的預設建構函式不同,即使我們定義了其他建構函式,也會合成複製建構函式。合成複製建構函式的行為是,執行逐個成員初始化,將新物件初始化為原物件的副本。

所謂「逐個成員」,指的是編譯器將現在物件的每個非 static 成員,依次複製到正建立的物件。只有乙個例外,每個成員摟型別決定了複製該成員的含義。合成複製建構函式直接複製內建型別成員的值,類型別成員使用該類的複製建構函式進行複製。陣列成員的複製是個例外。雖然一般不能複製陣列,但如果乙個類具有陣列成員,則合成複製建構函式將複製陣列。複製陣列時合成複製建構函式將複製陣列的每乙個元素。

逐個成員初始化最簡單的概念模型是,將合成複製建構函式看作這樣乙個建構函式:其中每個資料成員在建構函式初始化列表中進行初始化。

3.自定義的建構函式

複製建構函式就是接受單個類型別引用形參(通常用 const 修飾)的建構函式:

class foo ;
通常,定義複製建構函式最困難的部分在於認識到需要複製建構函式。只要能認識到需要複製建構函式,定義建構函式一般非常簡單。複製建構函式的定義與其他建構函式一樣:它與類同名,沒有返回值,可以(而且應該)使用建構函式初始化列表初始化新建立物件的成員,可以在函式體中做任何其他必要工作。

4.禁止複製

有些類需要完全禁止複製。例如,iostream 類就不允許複製.如果想要禁止複製,似乎可以省略複製建構函式,然而,如果不定義複製建構函式,編譯器將合成乙個。

為了防止複製,類必須顯式宣告其複製建構函式為 private。

如果複製建構函式是私有的,將不允許使用者**複製該類型別的物件,編譯器將拒絕任何進行複製的嘗試。然而,類的友元和成員仍可以進行複製。如果想要連友元和成員中的複製也禁止,就可以宣告乙個(private)複製建構函式但不對其定義。

宣告而不定義成員函式是合法的,但是,使用未定義成員的任何嘗試將導致鏈結失敗。通過宣告(但不定義)private 複製建構函式,可以禁止任何複製類型別物件的嘗試:使用者**中複製嘗試將在編譯時標記為錯誤,而成員函式和友元中的複製嘗試將在鏈結時導致錯誤。

二.賦值操作符

1.過載賦值介紹

2.合成賦值操作符

合成賦值操作符與合成複製建構函式的操作類似。它會執行逐個成員賦值:右運算元物件的每個成員賦值給左運算元物件的對應成員。除陣列之外,每個成員用所屬型別的常規方式進行賦值。對於陣列,給每個陣列元素賦值。

3.複製和賦值常一起使用

三.析構函式

析構函式的乙個用途是自動**資源。一般來說撤銷類物件時會自動呼叫析構函式來釋放類的成員,但是對於在程式執行過程中動態分配的物件,則只有指向該物件的指標被刪除時才可以撤銷,由此容易導致記憶體洩漏問題。因此應將動態物件的釋放寫入到析構函式中去。

1、何時編寫析構函式

析構函式通常用於釋放在建構函式或在物件生命期內獲取的資源。

如果類需要析構函式,則它也需要賦值操作符和複製建構函式

2、合成析構函式

與複製建構函式和賦值運算子不同,編譯器總是為我們合成乙個析構函式,合成析構函式按物件建立時的逆序撤銷每個非static成員

3、如何編寫析構函式

(1)析構函式是乙個成員函式,無返回值,無形參

(2)析構函式不可以過載

(3)乙個類可以定義多個建構函式,但是只能定義乙個析構函式

(4)析構函式與複製建構函式和賦值運算子之間的乙個重要區別是:即使編寫了自己的析構函式,合成析構函式仍然執行(先執行自己的析構函式,再執行合成 的析構函式)

四.例子

理解複製控制成員和建構函式的乙個方法就是定義乙個簡單類,下面程式有助於我們理解複製控制中的基本概念,幫助我們理解何時執行哪個建構函式和複製控制成員,

#include #include using namespace std;

class exmpl

exmpl(const exmpl&)

exmpl& operator = (const exmpl& rhs)

~exmpl()

};void fun1(exmpl obj)

void fun2(exmpl& obj)

exmpl fun3()

int main()

上述程式在vc6.0上執行結果如下圖:

在vs2010中,其執行結果為,並對其進行分析:

從上述結果可以看出來:不同的編譯器對順序容器的初始化採用不同的方式,在vc6.0中,先呼叫預設建構函式建立乙個臨時值物件exmpl,然後3次呼叫複製建構函式,將臨時值物件複製到vector中的每個元素中去,最後呼叫析構函式撤銷臨時物件exmpl。在vs2010中,可參考上述注釋。

C Primer筆記 13 複製控制

當定義乙個新型別的時候,需要顯式或隱式地指定複製 賦值和撤銷該型別的物件時會發生什麼 這就是通過定義特殊成員 複製建構函式 賦值操作符和析構函式來達到的。如果沒有顯式定義複製建構函式或賦值操作符,編譯器會為我們定義。複製建構函式 賦值操作符和析構函式總稱為複製控制 copy constrol 編譯器...

C Primer筆記之複製控制

複製控制這一節需要注意的地方不多,主要有以下幾點 1 定義自己的複製建構函式 什麼時候需要定義自己的複製建構函式,而不用系統提供的,主要遵循以下的經驗說明 某些類必須對複製物件時發生的事情加以控制,這樣的類 1 經常有乙個資料成員是指標,2 有成員在建構函式中分配的其他資源 而另一些類在建立物件時必...

C Primer 複製控制

複製建構函式 當定義乙個新物件並用乙個同型別的物件對它進行初始化時,將顯式使用複製建構函式 a a a 當將該型別的物件傳遞給函式或從函式返回該型別的物件時,將隱式使用複製建構函式 顯式使用和隱式使用的區別?析構函式 當物件超出作用域或動態分配的物件被刪除時,將自動應用析構函式。複製建構函式,賦值操...