Day18.拷貝建構函式呼叫時機,深拷貝與淺拷貝
阿新 • • 發佈:2021-12-17
拷貝建構函式的呼叫時機
-
使用一個已經建立完畢的物件初始化一個新物件
-
以值傳遞的方式給函式傳值
-
以值方式返回區域性物件
Person類
class Person { public: Person() { cout << "Person類的無參構造" << endl; } Person(string name,int a) { this->name = name; this->age = a; cout << "Person類的有參構造" << endl; } //拷貝建構函式:引用是傳入張三本體進行拷貝,const是防止修改張三本體 Person(const Person &p) { this->age = p.age;//將傳入的人身上的所有屬性拷貝到我身上 this->name = p.name; cout << "Person類的拷貝建構函式" << endl; } int age; string name; void show() { cout<< this->name << endl; cout << this->age << endl; } ~Person() { cout << "Person類的解構函式" << endl; } };
呼叫
//1. 使用一個已經建立完畢的物件初始化一個新物件 void test() { Person p1 = Person("小明", 20); Person p2 = Person(p1); } //2. 以值傳遞的方式給函式傳值void doWork(Person p){} void test1() { Person p; doWork(p); } int main() { test1(); //值傳遞會複製出一個形參在函式中進行操作,當引數為物件時會呼叫拷貝建構函式 system("pause"); return 0; }
值傳遞物件輸出:
//3. 以值方式返回區域性物件 Person doWork1() { Person p; return p; } void test2() { Person p = doWork1(); } int main() { test2(); //doWork1()中以值方式返回一個物件p,返回的p不是原來建立的物件,而是建立了一個新物件返回,在這個過程中呼叫了拷貝建構函式 system("pause"); return 0; }
側面驗證一下doWork1()中的p和test2()中的p是不是同一個
拷貝構造是類內有指標的情況下必寫的(賦值運算子過載是有需要的話)
老師這兩節課是在講,如果你有了一個物件,如何用函式再創造出一個來,拷貝構造就是完全複製一個現有物件
呼叫規則:
淺拷貝和深拷貝
淺拷貝:簡單的賦值拷貝操作
深拷貝:在堆區重新申請空間進行拷貝操作
報錯
問題解釋:
p1在進行有參初始化時,在堆區申請了一個空間,p1的height指標就指向這個空間,p2在進行拷貝初始化時使用的是編譯器提供的淺拷貝,淺拷貝是對成員變數的簡單賦值,所以p2的height指標=p1的height指標,即兩個height指標指向堆區的同一個地址,函式test01結束後,p1和p2把同一個空間釋放了兩次,所以程式崩了
兩個指標指向同一塊堆空間,區域性變數存在棧中,具有先進後出的特點,所以test1中後建立的p2先被釋放,執行解構函式,釋放掉堆區記憶體空間,再釋放p1指向的堆區記憶體空間,由於已經被釋放掉,非法操作,所以報錯
這是淺拷貝帶來的問題:堆區的記憶體重複釋放
解決方法:利用深拷貝,再開闢一塊堆空間存放175
/*淺拷貝與深拷貝*/ class Person { public: Person() { cout << "Person類的無參構造" << endl; } Person(int a,int height) { this->age = a; this->height= new int(height); cout << "Person類的有參構造" << endl; } Person(const Person &p) { this->age = p.age;//將傳入的人身上的所有屬性拷貝到我身上 //this->height = p.height; 這是編譯器預設的方式 //深拷貝方式 this->height = new int(*p.height); cout << "Person類的拷貝建構函式" << endl; } int age; int* height; ~Person() { if (height != NULL) { delete height;//把指標指向的堆空間釋放 height = NULL;//把指標本身釋放 } cout << "Person類的解構函式" << endl; } }; void test1() { Person p1(18,175); cout << "p1的年齡:" << p1.age << endl; cout << "p1的身高:" << *p1.height << endl; Person p2(p1); cout << "p2的年齡:" << p2.age << endl; cout << "p2的身高:" << *p2.height << endl; } int main() { test1(); system("pause"); return 0; }
如果屬性有在堆區開闢的,一定要自己寫拷貝建構函式,防止淺拷貝帶來的問題