C Primer 第十三章 複製控制

2022-02-23 05:28:49 字數 3563 閱讀 4709

複製建構函式、賦值操作符和析構函式總稱為複製控制。編譯器自動實現這些操作,但類也可以定義自己的版本。

複製建構函式是一種特殊建構函式,具有單個形參,該形參(常用 const 修飾)是對該類型別的引用。

析構函式是建構函式的互補:當物件超出作用域或動態分配的物件被刪除時,將自動應用析構函式。不管類是否定義了自己的析構函式,編譯器都會自動為類中非 static 資料成員執行析構函式。

賦值操作符與建構函式一樣,賦值操作符可以通過指定不同型別的右運算元而過載。右運算元為類型別的版本比較特殊:如果我們沒有編寫這種版本,編譯器將為我們合成乙個。 

class myclass

; //

複製建構函式

~myclass(){}; //

析構函式

myclass& operator=(const myclass &obj){}; //

賦值操作符

private:

int age;

string name;

}

13.1 複製建構函式

編譯器合成的複製控制函式是非常精練的——它們只做必需的工作。但對某些類而言,依賴於預設定義會導致災難。實現複製控制操作最困難的部分,往往在於識別何時需要覆蓋預設版本。有一種特別常見的情況需要類定義自己的複製控制成員的:類具有指標成員。

複製建構函式在下列情況下會被呼叫:

myclass obj1;

myclass obj2 = obj1; //

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

myclass fun(myclass par)

fun(obj1); //

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

vector svec(5);; //

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

myclass ls;//

根據物件初始化陣列

myclass ls; //

按照書上說是會呼叫複製建構函式但實際不會呼叫,據說是做了優化

如果不提供顯示的複製建構函式系統會合成乙個。合成的建構函式會在上述情況發生時會賦值物件副本並將物件資料成員逐一初始化成與原物件相同的值。

有個有趣的現象:陣列是不能複製的,但如果物件資料成員是個陣列型別卻可以複製陣列給物件副本的對應成員,合成複製建構函式模型如下

myclass(const myclass &obj):age(obj.age),name(obj.name)

如果想禁止複製可以顯示宣告私有的複製建構函式(最好不要這麼做否則類只能作為指標或引用傳遞),複製建構函式屬於建構函式,一旦定義複製建構函式應該給類顯示同時定義乙個預設建構函式。

13.2 賦值操作符   

類的賦值操作符實際上是操作符過載(operator=

賦值操作結果和拷貝建構函式類似,它會執行逐個成員賦值(複製構造是逐個成員初始化,然後也允許重新賦值)

myclass& operator=(const myclass &obj)

賦值操作符和複製建構函式幾乎可以看做乙個整體,如果需要其中乙個幾乎肯定也需要另外乙個。

關於操作符過載會在後續章節做詳細介紹。

13.3 析構函式

析構函式乙個用途是物件在銷毀之前做一些相關操作,比如清理資源,重新整理緩衝區等。析構函式在物件即將銷毀前執行

class he;};

int main()

//輸出:

item3 is delete!

item2 is delete!

item1 is delete!

delete list

li si is delete!

delete li si

zhang san is delete!

賦值操作和複製(拷貝)建構函式效果類似,在使用=號操作時有時候會呼叫賦值有時候會呼叫複製建構函式,怎麼區分呼叫方式呢?

複製(拷貝)建構函式,是用乙個已知的物件去初始化另乙個正在建立的物件;賦值操作,是用乙個已經存在的物件去更新另乙個已經存在的物件。

myclass a;

myclass b = a;  // 用乙個已知的物件去初始化另乙個正在建立的物件,呼叫複製建構函式

b = a;  // 用乙個已經存在的物件去更新另乙個已經存在的物件,呼叫賦值操作

賦值操作符可以通過指定不同型別的右運算元而過載,看**

class myclass

; //

賦值操作符

myclass& operator=(string str); //

賦值操作符過載

private:

string name;

}myclass a;

myclass b;

b = a;     //

呼叫 operator=(const myclass &obj)版

b = "

tom"; //

呼叫 operator=(string str)版

本章最後介紹了智慧型指標的概念。它不是c++具體技術而是解決拷貝物件時指標欄位會可能會引發錯誤的解決方案

//

類資料成員指標類

class myclass;//

智慧型指標

class curr;//

最後乙個擁有指標成員的物件消亡時會刪除智慧型指標物件,析構函式執行刪除真正指向的類物件

~curr()

;myclass *cur;

int used;

};//

具體類

class test

; test(const test &t): pro(t.pro) ,name(t.name) ,age(t.age)

;~test()

};void show();

private:

curr *pro;

string name;

int age;

};int main()

智慧型指標基本思路是用智慧型指標物件替換資料成員類物件指標,由智慧型指標維護物件指向。當具體類發生拷貝或刪除時更新智慧型指標維護的計數器。如果計數器==0說明所有具體類都消亡,刪除智慧型指標。智慧型指標再負責刪除資料成員物件。

第十三章 複製控制

1 複製建構函式,在物件定義初始化時,會出現 此時的 不是賦值效果,而是複製建構函式的效果。2 複製建構函式,定義在私有中,則禁止了操作,除了友元 若在私有中只是宣告不定義,則任何都無法呼叫建構函式 3 容器是有複製建構函式的。4 類中指標成員有3種處理方式,一是複製指標的值共享所指物件,這樣會帶來...

C Primer 第十三章 拷貝控制

當定義乙個類時,我們顯式或隱式指定在此型別的物件執行拷貝,移動,賦值,銷毀時做什麼,通過拷貝建構函式,拷貝賦值運算子,移動建構函式,移動賦值運算子和析構函式。拷貝賦值與銷毀 如果建構函式的第乙個引數是自身類型別的引用,並且其他引數都有預設值,則此建構函式是拷貝建構函式。第乙個引數一定是引用型別,並且...

第十三章 拷貝控制

在定義任何 c 類時,拷貝控制操作都是必要部分。如果我們不顯示定義這些操作,編譯器也會為我們定義,但編譯器定義的版本的行為可能並非我們所想。拷貝初始化不僅在我們用 定義變數時會發生,在下列情況下也會發生 將乙個物件作為實參傳遞給乙個非引用型別的形參 從乙個返回型別為非引用型別的函式返回乙個物件 用花...