1、構造函數
在C++面向對象程序設計中,通過構造函數對對象進程初始化,它可以為對象在計算機內存中開辟內存空間,也可以為對象的數據成員提供初始值。構造函數時一個與類同名,沒有返回值的特殊成員函數,每當創建一個對象時(包括使用new動態創建對象),編譯系統就會自動調用構造函數。構造函數像類以外的一般函數和類成員函數一樣,可以重載和帶缺省參數,構造函數的重載為對象的生成提供了各種靈活的手段。
構造函數分為缺省構造函數(默認構造函數)和用戶自定義構造函數。當程序員沒有定義構造函數時,系統就會提供一個無參的缺省構造函數,如果用戶自定義了一個構造函數,編譯器提供的缺省構造函數就自動消失了。

2、拷貝構造函數(復制構造函數)
拷貝構造函數的功能是一個已有的對象來初始化一個被創建的同類的對象,是一種特殊的構造函數,具有一般構造函數的所有特性,其形參是本類對象的引用。用戶可以根據自己實際問題的需要定義特定的拷貝構造函數,以實現同類對象之間數據成員的傳遞。如果用戶沒有聲明類的拷貝構造函數,系統就會自動生成一個缺省拷貝構造函數,這個缺省拷貝構造函數的功能是把初始的每個數據成員的值都復制到新建立的對象中。拷貝構造函數的聲明如下:
類名(類型 & 對象名);
class people
{
public:
void dipalay()
{
}
private:
int a;
char*name;
};
調用拷貝構造函數有以下三種情況:
(1)用類的一個對象去初始化另一個對象時。
(2)對象作為函數參數傳遞時,調用拷貝構造函數
(3)如果函數的返回值是類的對象,函數調用返回時,調用拷貝構造函數。

3、淺拷貝和深拷貝
拷貝就是復制,創建副本。假設有對象A,A有屬性t1,t2。那么,我通過拷貝A,得到B,B應該也有屬性t1,t2,且A、B兩個對象的每個屬性,都應該是相同的。
對於基本類型的屬性t1,拷貝是沒有疑義的。簡單將值復制一份,就達到了拷貝的效果。而對於引用類型的屬性t2來說,拷貝就有了兩層含義。
第一層是,我只是將t2引用的地址復制一份給B的t2,確實達到了屬性相同的效果,可以理解為實現了拷貝,但是事實上,兩個對象中的屬性t2對應的是同一個對象。在B對象上對t2所指向的對象進行操作,就會影響到A對象中的t2的值。
第二層是,我將A的t2所指向的對象,假設為o1,完整復制一份,假設為o2,將新的o2的地址給B的t2。也達到了復制的效果,且對B的t2所指向的o2進行操作,不會影響到A的t2所指向的o1。
拷貝的兩層含義,對應了淺拷貝和深拷貝的概念,做了第一層,就是淺拷貝,做到第二層,就是深拷貝。
基於以上內容,很容易可以想到,淺拷貝比深拷貝要更快,但是,從拷貝的意義上來看,淺拷貝相較於深拷貝,要欠缺一點。

總結一下:
淺拷貝:位拷貝,拷貝構造函數,賦值重載
多個對象共用同一塊資源,同一塊資源釋放多次,崩潰或者內存泄漏
深拷貝:每個對象共同擁有自己的資源,必須顯式提供拷貝構造函數和賦值運算符。
簡而言之:深拷貝和淺拷貝可以簡單理解為:如果一個類擁有資源,當這個類的對象發生復制過程的時候,資源重新分配,這個過程就是深拷貝,反之,沒有重新分配資源,就是淺拷貝。

實例如下:
#include <iostream>using namespace std;
class CopyDemo{public: CopyDemo(int pa,char *cstr) //構造函數,兩個參數 { this->a = pa; this->str = new char[1024]; //指針數組,動態的用new在堆上分配存儲空間 strcpy(this->str,cstr); //拷貝過來 }
//沒寫,C++會自動幫忙寫一個復制構造函數,淺拷貝只復制指針,如下注釋部分 //CopyDemo(CopyDemo& obj) //{ // this->a = obj.a; // this->str = obj.str; //這里是淺復制會出問題,要深復制 //}
CopyDemo(CopyDemo& obj) //一般數據成員有指針要自己寫復制構造函數,如下 { this->a = obj.a; // this->str = obj.str; //這里是淺復制會出問題,要深復制 this->str = new char[1024];//應該這樣寫 if(str != 0) strcpy(this->str,obj.str); //如果成功,把內容復制過來 }
~CopyDemo() //析構函數 { delete str; }
public: int a; //定義一個整型的數據成員 char *str; //字符串指針};
int main(){ CopyDemo A(100,"hello!!!");
CopyDemo B = A; //復制構造函數,把A的10和hello!!!復制給B cout <<"A:"<< A.a << "," <<A.str << endl; //輸出A:100,hello!!! cout <<"B:"<< B.a << "," <<B.str << endl; //輸出B:100,hello!!!
//修改后,發現A,B都被改變,原因就是淺復制,A,B指針指向同一地方,修改后都改變 B.a = 80; B.str[0] = 'k';
cout <<"A:"<< A.a << "," <<A.str << endl; //輸出A:100,kello!!! cout <<"B:"<< B.a << "," <<B.str << endl; //輸出B:80,kello!!!
return 0;}
根據上面實例可以看到,淺復制僅復制對象本身(其中包括是指針的成員),這樣不同被復制對象的成員中的對應非空指針會指向同一對象,被成員指針引用的對象成為共享的,無法直接通過指針成員安全地刪除(因為若直接刪除,另外對象中的指針就會無效,形成所謂的野指針,而訪問無效指針是危險的;除非這些指針有引用計數或者其它手段確保被指對象的所有權);
而深復制在淺復制的基礎上,連同指針指向的對象也一起復制,代價比較高,但是相對容易管理。
小結:
深拷貝和淺拷貝最根本的區別在於是否真正獲取一個對象的復制實體,而不是引用。
假設B復制了A,修改A的時候,看B是否發生變化:
如果B跟着也變了,說明是淺拷貝,拿人手短!(修改堆內存中的同一個值)
如果B沒有改變,說明是深拷貝,自食其力!(修改堆內存中的不同的值)
淺拷貝(shallowCopy)只是增加了一個指針指向已存在的內存地址,
深拷貝(deepCopy)是增加了一個指針並且申請了一個新的內存,使這個增加的指針指向這個新的內存,
使用深拷貝的情況下,釋放內存的時候不會因為出現淺拷貝時釋放同一個內存的錯誤。

如果你想更好的提升你的編程能力,學好C語言C++編程!彎道超車,快人一步!
【C語言C++學習企鵝圈子】,分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)
歡迎轉行和學習編程的伙伴,利用更多的資料學習成長比自己琢磨更快哦!
編程學習書籍:

編程學習視頻:

原文鏈接:https://mp.weixin.qq.com/s/emgZO229CTrtiJidAojpHA