1.定義:
我們對一個已知對象拷貝時,編譯系統會自動調用一種拷貝構造函數——拷貝構造函數,如果用戶未定義拷貝構造函數,
則會默認調用拷貝構造函數
淺拷貝,是由缺省的拷貝構造函數所實現的數據成員逐一進行賦值,如果類中含有指針則會產生錯誤。
為了解決淺拷貝出現的錯誤,我們可以定義一個拷貝構造函數,使之不僅僅拷貝數據成員,為對象1和對象2分配各自
的內存空間。這就是所謂的深拷貝
簡單來說:淺拷貝拷貝的是指針變量地址,深拷貝會重新開辟內存空間。
2.示例
我們用一個例子來了解一下拷貝構造的去淺拷貝和深拷貝:
我們對student對象進行淺拷貝,對象包含指針
#include<iostream> using namespace std; class Student { private: char* name; int age; public: Student() { name = new char(20); cout << "Student" << endl; } ~Student() { cout << "destroy Student!" << endl; delete name; //這里會delete兩次,第二次程序會直接崩掉 name = NULL; } }; int main() { Student s1; Student s3(s1); return 0; }
代碼執行結果:
我們發現在拷貝構造時候,在函數析構時后程序崩掉了。
此時我們調用了兩次析構函數,指針所指的內存釋放了兩次!但我們構造函數指針只分配了一次內存
造成了內存泄漏
我們發現對存在指針的對象進行淺拷貝后會出現兩個指針指向同一個內存空間的情況
所以我們為了避免內存泄漏對含有指針成員的對象進行拷貝時,必須要自己定義拷貝構造函數,使拷
貝后的對象指針成員有自己的內存空間,這就是深拷貝的方式。(還可以引入引用技術設計或智能指
針,后邊博客會講道)
深拷貝代碼:
#include<iostream> #include<string.h> using namespace std; class Student { char* name; int age; public: Student(); ~Student(); Student(const Student& s); }; Student::Student() { name = new char(20); cout << "Build Student" << endl; } Student::~Student() { cout << "destory Student" <<(int)name<<endl; delete name; name = NULL; } Student::Student(const Student& s) { name = new char(20); memcpy(name, s.name, strlen(s.name)); //同時將內存地址也拷貝過去 cout << "copy Student" << endl; } int main() { Student stu1; Student stu2(stu1); return 0; }
代碼執行結果:
深拷貝經過一次構造函數,一次自定義拷貝構造函數,兩次析構函數。且兩個對象的指針成員所指內存不同,我們最終完成了
對指針進行的拷貝構造