1.拷貝建構函式的定義:如果乙個建構函式的第乙個引數是自身型別的引用,且任何額外引數都有預設值。
!拷貝建構函式的第乙個引數必須是乙個引用型別。
合成拷貝建構函式:
如果我們沒有為乙個類定義拷貝建構函式,編譯器會為我們定義乙個。編譯器從給定物件中,依次將每個非static成員拷貝到正在建立的物件中。
2.拷貝初始化:
拷貝初始化不僅在我們使用=定義變數時會發生,在下列情況下也會:
拷貝建構函式自己的引數必須是引用型別,如果其引數不是引用型別,則呼叫永遠也不會成功——為了呼叫拷貝建構函式,我們必須拷貝它的實參,但為了拷貝實參,我們又必須呼叫拷貝建構函式,如此無限迴圈。
拷貝建構函式在用類的乙個物件去初始化該類的另乙個物件時呼叫,以下三種情況相當於用乙個已存在的物件去初始化新建立的物件,此時,呼叫拷貝建構函式:
1.當用類的乙個物件去初始化該類的另乙個物件時。
2.如果函式的形參是類的物件,呼叫函式時,將物件作為函式實參傳遞給函式的形參時。
3.如果函式的返回值是類的物件,函式執行完成時,將返回值返回。
注意:1>拷貝建構函式只是在用乙個已存在的物件去初始化新建立的物件時呼叫,而物件進行賦值時,拷貝函式將不被呼叫。
2>用乙個常量初始化新建立的物件時,呼叫建構函式,不呼叫拷貝建構函式
3>建立物件時,建構函式與拷貝建構函式只有乙個被呼叫
4> 當物件作為函式的返回值時需要呼叫拷貝建構函式,此時c++將從堆中動態建立乙個臨時物件,將函式返回的物件拷貝給該臨時物件,並把該臨時物件的位址儲存在暫存器裡,從而由該臨時物件完成函式返回值的傳遞
3.淺拷貝與深拷貝
預設的拷貝建構函式實現的只能是淺拷貝,即直接將原物件的資料成員值依次複製給新物件中對應的資料成員,並沒有為新物件另外分配記憶體資源。
這樣,如果物件的資料成員是指標,兩個指標物件實際上指向的是同一塊記憶體空間。
在某些情況下,淺拷貝回帶來資料安全方面的隱患。
當類的資料成員中有指標型別時,我們就必須定義乙個特定的拷貝建構函式,該拷貝建構函式不僅可以實現原物件和新物件之間資料成員的拷貝,而且可以為新的物件分配單獨的記憶體資源,這就是深拷貝建構函式。
淺拷貝存在的問題:
#includeusing namespace std;
class rect
~rect()
private:
int width;
int height;
int *p;
};int main()
程式執行時會發生錯誤,在銷毀物件時,兩個物件的建構函式將對同乙個記憶體空間釋放兩次。
由於合成的預設拷貝建構函式是淺拷貝,在使用rect1複製rect2時,由於執行的是淺拷貝,只是將成員的值進行賦值,這時
rect1.p
= rect2.p
,也即這兩個指標指向了堆裡的同乙個空間。
所以必須要用深拷貝,自己定義拷貝建構函式:
#includeusing namespace std;
class rect
rect(const rect& r)
~rect()
private:
int width;
int height;
int *p;
};
3.防止預設拷貝發生
宣告乙個私有的拷貝建構函式,這樣因為拷貝建構函式是私有的,如果使用者試圖按值傳遞或函式返回該類的物件,編譯器會報告錯誤,從而可以避免按值傳遞或返回物件。
總結:當出現類的等號賦值時,會呼叫拷貝函式,在未定義顯示拷貝建構函式的情況下,系統會呼叫預設的拷貝函式
——即淺拷貝,它能夠完成成員的一一複製。當資料成員中沒有指標時,淺拷貝是可行的。但當資料成員中有指標時
,如果採用簡單的淺拷貝,則兩類中的兩個指標將指向同乙個位址,當物件快結束時,會呼叫兩次析構函式,而導致指標懸掛現象。所以,這時,必須採用深拷貝。
深拷貝與淺拷貝的區別就在於深拷貝會在堆記憶體中另外申請空間來儲存資料,從而也就解決了指標懸掛的問題。簡而言之,當資料成員中有指標時,必須要用深拷貝。
參考部落格:
關於拷貝建構函式
首先不要使用vc編譯器來測試,看看這段 並猜想它會呼叫幾次建構函式和析構函式,最後再測試一下 在vc編譯執行後結果大失所望吧?不明白不要緊,vc這個整合的ide開發工具它的 博大精深 值得我們慢慢學習與積累,先看看下面我查詢的資料吧 一 拷貝建構函式 拷貝建構函式,是一種特殊的建構函式,它由編譯器呼...
關於拷貝建構函式
1 乙個物件用於給另外乙個物件進行初始化 賦值初始化 2 乙個物件作為函式引數,以值傳遞的方式傳入函式體 3 乙個物件作為函式返回值,以值傳遞的方式從函式返回 原則 對於凡是包含動態分配成員或包含指標成員的類都應該提供拷貝建構函式 對於第一種情況,先用乙個例子進行以下的說明 這個類的主要特點是包含指...
深淺拷貝問題 拷貝建構函式
深拷貝 在堆區重新申請空間,進行拷貝操作 淺拷貝 簡單的複製拷貝操作 class person person int age person int m age void test 當引數中有堆區引數,改造之後 class person person int age,int height person...