C 拷貝建構函式

2021-09-23 21:23:17 字數 2972 閱讀 3600

對於普通型別的物件來說,它們之間的複製是很簡單的,例如:

int a=88;

int b=a;

而類物件與普通物件不同,類物件內部結構一般較為複雜,存在各種成員變數。

1、物件的定義形式

c++支援兩種定義形式:直接初始化和複製初始化,複製初始化採用=符號,直接初始化將初始化式放在圓括號中

用於類型別物件時,直接初始化直接呼叫與實參匹配的建構函式,複製初始化總是呼叫拷貝建構函式,複製初始化首先使用指定建構函式建立乙個臨時物件,然後拷貝建構函式將那個臨時物件拷貝到正在建立的物件

string null_book="

9-454-45546

"; //

複製初始化

string dots(10,'

.'); //

直接初始化

string empty_copy=string(); //

複製初始化

string empty_direct; //

直接初始化

通常,直接初始化和複製初試化只在低級別優化上存在差異,但是對於不支援複製的型別,或者使用非explicit建構函式的時候,它們就有本質的區別:

ifstream file1("

filename

"); //

okifstream file2="

filename

"; //

error! 複製建構函式是私有的

2、形參與返回值

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

3、初始化容器元素

複製初始化函式可用於初始化順序容器中的元素,容器的這種構造方式使用了預設建構函式和拷貝建構函式:

vectorsvec(5);

4、建構函式與陣列元素

如果沒有為類型別陣列提供元素的初始化形式,則將使用預設建構函式初始化每個元素,然而,如果使用常規的花括號括住的陣列初始化列表來提供顯示元素的初始化式,則使用複製初始化來初始化每個元素:

a a=;
如果沒有定義拷貝建構函式,編譯器會為我們合成乙個,即使我們定義了其他的建構函式,也會合成拷貝建構函式。合成拷貝建構函式的行為是,執行逐個成 員的初始化。編譯器將現有物件的每個非static成員,依次複製到正建立的物件,合成拷貝建構函式直接複製內建型別成員的值,類型別成員使用該類的拷貝 建構函式進行複製,陣列成員使用合成拷貝建構函式將複製陣列的每乙個元素

class a;

a::a(const a &a):s(a.s),n(a.n),b(a.b){}

定義自己的拷貝建構函式

class a;
下面看乙個類物件拷貝的簡單例子:

#includeusing

namespace std;

class a

void print()

執行程式,螢幕輸出100。從以上**的執行結果可以看出,系統為物件a1分配了記憶體並完成了與物件a的拷貝過程。就類物件而言,相同型別的類物件是通過拷貝建構函式來完成整個複製過程的。下面舉例說明拷貝函式的工作過程:

#includeusing

namespace std;

class a

a(const a& c)

void print()

a(const a& c)就是我們自定義的拷貝建構函式。可見,拷貝建構函式是一種特殊的建構函式,函式的名稱必須和類名稱一致,它的唯一的乙個引數是本型別的乙個引用變數,該引數是const型別,不可變的。例如:類x的拷貝建構函式的形式為x(x& x)。

當用乙個已初始化過了的自定義類型別物件去初始化另乙個新構造的物件的時候,拷貝建構函式就會被自動呼叫。也就是說,當類的物件需要拷貝時,拷貝建構函式將會被呼叫。以下情況都會呼叫拷貝建構函式:

乙個物件以值傳遞的方式傳入函式體

乙個物件以值傳遞的方式從函式返回

乙個物件需要通過另外乙個物件進行初始化

如果在類中沒有顯式地宣告乙個拷貝建構函式,那麼,編譯器將會自動生成乙個預設的拷貝建構函式,該建構函式完成物件之間的位拷貝。位拷貝又稱淺拷貝,後面將進行說明。自定義拷貝建構函式是一種良好的程式設計風格,它可以阻止編譯器形成預設的拷貝建構函式,提高原始碼效率。

在某些狀況下,類內成員變數需要動態開闢堆記憶體,如果實行位拷貝,也就是把物件裡的值完全複製給另乙個物件,如a=b。這時,如果b中有乙個成員 變數指標已經申請了記憶體,那a中的那個成員變數也指向同一塊記憶體。這就出現了問題:當b把記憶體釋放了(如:析構),這時a內的指標就是野指標了,出現執行 錯誤。

深拷貝和淺拷貝可以簡單理解為:如果乙個類擁有資源,當這個類的物件發生複製過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。下面舉個深拷貝的例子:

#include#include#include

using

namespace std;

class a

a(const a& c)

void print()

深拷貝和淺拷貝的定義可以簡單理解成:如果乙個類擁有資源(堆,或者是其它系統資源),當這個類的物件發生複製過程的時候,這個過程就可以叫做深拷貝,反之物件存在資源,但複製過程並未複製資源的情況視為淺拷貝。

淺拷貝資源後在釋放資源的時候會產生資源歸屬不清的情況導致程式執行出錯。

拷貝建構函式的名稱必須與類名稱一致,函式的形式引數是本型別的乙個引用變數,且必須是引用。當用乙個已經初始化過了的自定義類型別物件去初始化另乙個新 構造的物件的時候,拷貝建構函式就會被自動呼叫,如果你沒有自定義拷貝建構函式的時候,系統將會提供給乙個預設的拷貝建構函式來完成這個過程

禁止複製

拷貝建構函式是私有的,將不允許使用者**複製該類型別的物件,但是類的友元和成員仍可以進行複製,如果連類的友元和成員也禁止,可以宣告乙個private建構函式但是不對其定義

C 建構函式 拷貝建構函式

建構函式 class base private int m var 建構函式無返回值型別,函式名和型別相同。拷貝建構函式傳遞引數為引用。1 class base2 7 拷貝建構函式 8 base base ref m var ref m var 9 11 private 12 intm var 13...

C 拷貝建構函式

1 什麼時候會用到拷貝建構函式?當任何你想影印東西的時候,而不管東西被影印成什麼樣子。即任何你想利用乙個已有的類例項給另乙個類例項賦值時,這種賦值可能是顯式的,也可能是隱式的 顯式 classa 1 class 2 隱式 函式的形參有用到類物件卻沒有用引用或傳址技術時 函式的返回值是乙個物件也沒有應...

C 拷貝建構函式

1 拷貝構造 copy建構函式用於將乙個物件拷貝到新建立的物件中。也就是說它用於初始化過程中,而不是常規的賦值過程中。一般的copy建構函式原型通常如下 class name const class name rhs 它接受乙個指向類物件的常量引用作為引數。例如,cstring類的拷貝建構函式的原型...