C 複製建構函式

2021-06-10 08:17:39 字數 3064 閱讀 6358

1. 概念:只有單個形參,而且該形參是對本類型別物件的引用(常用const修飾)。

2. 首先看乙個小例子:

.h中:

class test

private:

int a;

float b;

};.cpp中:

int  main()

test test1(5, 5.5);

test test2(1, 1.1);

coutcouttest3使用了編譯器提供的預設複製建構函式,即將類型別物件test1(與test3同型別)的非static成員複製給test3了(如有數組成員,則會逐個陣列元素複製。因為陣列不支援直接複製,只能遍歷複製,所以預設複製建構函式會進行遍歷複製陣列元素)。。  程式中沒有顯示提供複製建構函式,所以編譯器會合成乙個。

2. 顯示提供複製建構函式

.h中:

class test

test(int m,float n):a(m),b(n)

test &test(const test&);    //顯示宣告的複製建構函式

public:

int a;

float b;

};.cpp 中

test &test::test(const test& obj)

int main()

test test1(2, 5.4);

test test2;

test2.test(test1);     //呼叫複製建構函式

cout3.  深拷貝例項

.h檔案中

class test

test(int m,float n):a(m),b(n)

test &test(const test&);    //複製建構函式

~test()

public:

int a;

float b;

char *p;     //類中有指標成員,必須顯示定義複製建構函式

};.cpp中

test &test::test(const test& obj)

int main()

test test1(2, 5.4);

test test2;

test2.test(test1);          //呼叫複製建構函式

cout<4. 在c++中,下面三種物件需要拷貝的情況。因此,複製建構函式將會被呼叫。

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

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

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

如果在前兩種情況不使用複製建構函式的時候,就會導致乙個指標指向已經被刪除的記憶體空間(前提是:類中有指標成員)。事實上,複製建構函式是由普通建構函式和賦值操作符共同實現的。

在類的定義中,如果沒有顯式定義複製建構函式,c++編譯器會自動地定義乙個預設的複製建構函式。

5. 一般物件產生時都會觸發建構函式的執行,但是在產生物件的副本時卻不會這樣,這時執行的是物件的複製建構函式。為什麼會這樣?一般的建構函式都是會完成一些成員屬性初始化的工作,在物件傳遞給某一函式之前,物件的一些屬性可能已經被改變了,如果在產生物件副本的時候再執行物件的建構函式,那麼這個物件的屬性又再恢復到原始狀態,這並不是我們想要的。

所以在產生物件副本的時候,建構函式不會被執行,被執行的是乙個複製建構函式。當函式執行完畢要返回的時候,物件副本會執行析構函式,如果你的析構函式是空的話,就不會發生什麼問題,但一般的析構函式都是要完成一些清理工作,如釋放指標所指向的記憶體空間。這時候問題就可能要出現了。假如你在建構函式裡面為乙個指標變數分配了記憶體,在析構函式裡面釋放分配給這個指標所指向的記憶體空間,那麼在把物件傳遞給函式至函式結束返回這一過程會發生什麼事情呢?首先有乙個物件的副本產生了,這個副本也有乙個指標,它和原始物件的指標是指向同塊記憶體空間的。函式返回時,物件的析構函式被執行了,即釋放了物件副本裡面指標所指向的記憶體空間,但是這個記憶體空間對原始物件還是有用的啊,就程式本身而言,這是乙個嚴重的錯誤。然而錯誤還沒結束,當原始物件也被銷毀的時候,析構函式再次執行,對同一塊系統動態分配的記憶體空間釋放兩次是乙個未知的操作,將會產生嚴重的錯誤。

上面說的就是我們會遇到的問題. 複製建構函式就是在產生物件副本的時候執行的,我們要定義自己的複製建構函式。在複製建構函式裡面我們申請乙個新的記憶體空間來儲存建構函式裡面的那個指標所指向的內容。這樣在執行物件副本的析構函式時,釋放的就是複製建構函式裡面所申請的那個記憶體空間。即所謂的深拷貝問題。

除了將物件傳遞給函式時會存在以上問題,還有一種情況也會存在以上問題,就是當函式返回物件時,會產生乙個臨時物件,這個臨時物件和物件的副本性質差不多。

6. 如果乙個類中有指標成員,使用預設的複製建構函式初始化物件就會出現問題。為了說明存在的問題,我們假定物件a與物件b是相同的類,有乙個指標成員,指向物件c。當用物件b初始化物件a時,預設的複製建構函式將b中每乙個成員的值複製到a的對應的成員當中,但並沒有複製物件c,而只是複製的位址。也就是說,物件a和物件b中的指標成員均指向物件c,實際上,我們希望物件c也被複製,得到c的物件副本d。否則,當物件a和b銷毀時,會對物件c的記憶體區重複釋放,而導致錯誤。下面我們以string類為例說明,如何定義這個複製建構函式。

class string

上述演示了深拷貝的問題, 採取了新開闢記憶體的方式避免了記憶體歸屬不清所導致析構釋放空間時候的錯誤,

拷貝和淺拷貝的定義可以簡單理解成:如果乙個類擁有資源(堆,或者是其它系統資源),當這個類

的物件發生複製過程的時候,這個過程就可以叫做深拷貝,反之物件存在資源但複製過程並未複製

資源的情況視為淺拷貝。

綜上所述:

普通物件和類物件同為物件,他們之間的特性有相似之處也有不同之處,類物件內部存在成員變數

,而普通物件是沒有的,當同樣的複製方法發生在不同的物件上的時候,那麼系統對他們進行的操

作也是不一樣的,就類物件而言,相同型別的類物件是通過拷貝建構函式來完成整個複製過程的。

當乙個類沒有自定義的拷貝建構函式的時候系統會自動提供乙個預設的拷貝建構函式,來完成複製

工作。當用乙個已經初始化過了的自定義類型別物件去初始化另乙個新構造的物件的時候,拷貝建構函式

就會被自動呼叫,如果你沒有自定義拷貝建構函式的時候系統將會提供給乙個預設的拷貝建構函式

來完成這個過程。

C 複製建構函式

c 複製建構函式,一般在一下幾種情況中出現 1 物件以值傳遞的方式傳入函式時 2 物件以值傳遞的的方式從函式返回 3 乙個物件通過另乙個物件初始化 4 陣列 根據陣列中的初始化列表初始化陣列的時候。5 容器 初始化順序容器中的元素 有3種情況必須使用複製建構函式 a 如果有資料成員是指標 b 要在建...

C 複製建構函式

誰知道 include include using namespace std class person 如果兩種方式同時存在,會呼叫沒有const的版本 2.推薦,存在唯一的person person person person 3.不推薦,這個依然是複製建構函式,詭異。與第二種方法存在二義性 p...

複製建構函式(C )

複製建構函式定義 複製建構函式是一種特殊的建構函式,其形參為本類的物件引用。作用是用乙個已存在的物件去初始化同型別的新物件。class類名 類名 類 const 類名 物件名 複製建構函式的實現 複製建構函式被呼叫的三種情況 定義乙個物件時,以本類另 個物件作為初始值,發生複製構造 如果函式的形參是...