1. 程式人生 > 其它 >Day18.拷貝建構函式呼叫時機,深拷貝與淺拷貝

Day18.拷貝建構函式呼叫時機,深拷貝與淺拷貝

拷貝建構函式的呼叫時機

  1. 使用一個已經建立完畢的物件初始化一個新物件

  2. 以值傳遞的方式給函式傳值

  3. 以值方式返回區域性物件

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;
 }

如果屬性有在堆區開闢的,一定要自己寫拷貝建構函式,防止淺拷貝帶來的問題

P110結束

來源:b站黑馬