拷貝結構函數顧名思義就是復制對象。
先講一下默認拷貝函數:
默認拷貝就是直接賦值,讓程序調用默認拷貝結構函數。
Student p1; Student p2 = p1//或者Student p2(p1);
程序開始運行時,創建p1對象,p1對象的構造函數從堆中分配空間並賦給數據成員pName,執行,p2=p1時,因為沒有定義拷貝構造函數,於是就調用默認拷貝構造函數,
使得p2與p1完全一樣,並沒有新分配堆空間給p2, p1與p2的pName都是同一個值。析構p2時,將堆中字符串清成空串,然后將堆空間返還給系統;
析構p1時,因為這是pName指向的是空串,所以第三行輸出中顯示的只是Destructing,當執行 delete pName ; 按道理系統應該報錯,但在gcc中沒有。
重點講一下,深拷貝和淺拷貝。
這里借鑒一個前輩的例子:(前輩寫的很好,大家可以看下)
https://www.cnblogs.com/raichen/p/4752025.html
#include <iostream> #include <cstring> class Person { public : // 構造函數 Person(char * pN) { cout << "一般構造函數被調用 !\n"; m_pName = new char[strlen(pN) + 1]; //在堆中開辟一個內存塊存放pN所指的字符串 if(m_pName != NULL) { //如果m_pName不是空指針,則把形參指針pN所指的字符串復制給它 strcpy(m_pName ,pN); } } // 系統創建的默認復制構造函數,只做位模式拷貝 Person(Person & p) { //使兩個字符串指針指向同一地址位置 m_pName = p.m_pName; } ~Person( ) { delete m_pName; } private : char * m_pName; }; void main( ) { Person man("lujun"); Person woman(man); // 結果導致 man 和 woman 的指針都指向了同一個地址 // 函數結束析構時 // 同一個地址被delete兩次 } // 下面自己設計復制構造函數,實現“深拷貝”,即不讓指針指向同一地址,而是重新申請一塊內存給新的對象的指針數據成員 Person(Person & chs); { // 用運算符new為新對象的指針數據成員分配空間 m_pName=new char[strlen(p.m_pName)+ 1]; if(m_pName) { // 復制內容 strcpy(m_pName ,chs.m_pName); } // 則新創建的對象的m_pName與原對象chs的m_pName不再指向同一地址了 }
因為編譯不同,可能不能通過編譯,但這不是重點。
直接利用淺拷貝,m_pName = p.m_pName,后者復制給前者,但資源(堆空間)並未復制給前者,相當於這兩個都同時指向同一地址,造成或釋放兩次內存。
深拷貝上面例子可以看到,會給它新申請一個空間。
注意:(引用)“如果需要析構函數,則一定需要拷貝構造函數和賦值操作符。”
什么情況使用復制構造函數:
類的對象需要拷貝時,拷貝構造函數將會被調用。以下情況都會調用拷貝構造函數:
(1)一個對象以值傳遞的方式傳入函數體
(2)一個對象以值傳遞的方式從函數返回
(3)一個對象需要通過另外一個對象進行初始化。
同時別人推薦的讀的文章:https://blog.csdn.net/fdsafwagdagadg6576/article/details/51723823
想要了解跟多可以了解一下這篇文章:《面向對象進價--拷貝構造函數》
然后可以看下例子:多繼承的例子(附詳解)