詳解C++ 拷貝建構函式
拷貝建構函式是一種特殊的建構函式,它在建立物件時,是使用同一類中之前建立的物件來初始化新建立的物件。拷貝建構函式通常用於:
- 通過使用另一個同類型的物件來初始化新建立的物件。
- 複製物件把它作為引數傳遞給函式。
- 複製物件,並從函式返回這個物件。
如果在類中沒有定義拷貝建構函式,編譯器會自行定義一個。如果類帶有指標變數,並有動態記憶體分配,則它必須有一個拷貝建構函式。拷貝建構函式的最常見形式如下:
classname (const classname &obj) { // 建構函式的主體 }
在這裡,obj 是一個物件引用,該物件是用於初始化另一個物件的。
#include <iostream> using namespace std; class Line { public: int getLength( void ); Line( int len ); // 簡單的建構函式 Line( const Line &obj); // 拷貝建構函式 ~Line(); // 解構函式 private: int *ptr; }; // 成員函式定義,包括建構函式 Line::Line(int len) { cout << "呼叫建構函式" << endl; // 為指標分配記憶體 ptr = new int; *ptr = len; } Line::Line(const Line &obj) { cout << "呼叫拷貝建構函式併為指標 ptr 分配記憶體" << endl; ptr = new int; *ptr = *obj.ptr; // 拷貝值 } Line::~Line(void) { cout << "釋放記憶體" << endl; delete ptr; } int Line::getLength( void ) { return *ptr; } void display(Line obj) { cout << "line 大小 : " << obj.getLength() <<endl; } // 程式的主函式 int main( ) { Line line(10); display(line); return 0; }
當上面的程式碼被編譯和執行時,它會產生下列結果:
呼叫建構函式
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
釋放記憶體
下面的例項對上面的例項稍作修改,通過使用已有的同類型的物件來初始化新建立的物件:
#include <iostream> using namespace std; class Line { public: int getLength( void ); Line( int len ); // 簡單的建構函式 Line( const Line &obj); // 拷貝建構函式 ~Line(); // 解構函式 private: int *ptr; }; // 成員函式定義,包括建構函式 Line::Line(int len) { cout << "呼叫建構函式" << endl; // 為指標分配記憶體 ptr = new int; *ptr = len; } Line::Line(const Line &obj) { cout << "呼叫拷貝建構函式併為指標 ptr 分配記憶體" << endl; ptr = new int; *ptr = *obj.ptr; // 拷貝值 } Line::~Line(void) { cout << "釋放記憶體" << endl; delete ptr; } int Line::getLength( void ) { return *ptr; } void display(Line obj) { cout << "line 大小 : " << obj.getLength() <<endl; } // 程式的主函式 int main( ) { Line line1(10); Line line2 = line1; // 這裡也呼叫了拷貝建構函式 display(line1); display(line2); return 0; }
當上面的程式碼被編譯和執行時,它會產生下列結果:
呼叫建構函式
呼叫拷貝建構函式併為指標 ptr 分配記憶體
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
呼叫拷貝建構函式併為指標 ptr 分配記憶體
line 大小 : 10
釋放記憶體
釋放記憶體
釋放記憶體
關於為什麼當類成員中含有指標型別成員且需要對其分配記憶體時,一定要有總定義拷貝建構函式??
預設的拷貝建構函式實現的只能是淺拷貝,即直接將原物件的資料成員值依次複製給新物件中對應的資料成員,並沒有為新物件另外分配記憶體資源。
這樣,如果物件的資料成員是指標,兩個指標物件實際上指向的是同一塊記憶體空間。
在某些情況下,淺拷貝迴帶來資料安全方面的隱患。
當類的資料成員中有指標型別時,我們就必須定義一個特定的拷貝建構函式,該拷貝建構函式不僅可以實現原物件和新物件之間資料成員的拷貝,而且可以為新的物件分配單獨的記憶體資源,這就是深拷貝建構函式。
如何防止預設拷貝發生
宣告一個私有的拷貝建構函式,這樣因為拷貝建構函式是私有的,如果使用者試圖按值傳遞或函式返回該類的物件,編譯器會報告錯誤,從而可以避免按值傳遞或返回物件。
總結:
當出現類的等號賦值時,會呼叫拷貝函式,在未定義顯示拷貝建構函式的情況下,系統會呼叫預設的拷貝函式——即淺拷貝,它能夠完成成員的一一複製。當資料成員中沒有指標時,淺拷貝是可行的。但當資料成員中有指標時,如果採用簡單的淺拷貝,則兩類中的兩個指標將指向同一個地址,當物件快結束時,會呼叫兩次解構函式,而導致指標懸掛現象。所以,這時,必須採用深拷貝。
深拷貝與淺拷貝的區別就在於深拷貝會在堆記憶體中另外申請空間來儲存資料,從而也就解決了指標懸掛的問題。簡而言之,當資料成員中有指標時,必須要用深拷貝。
以上就是詳解C++ 拷貝建構函式的詳細內容,更多關於C++ 拷貝建構函式的資料請關注我們其它相關文章!