C++ | 深拷貝與淺拷貝的認識和區別

一、構造函數

在C++面向對象程序設計中,經過構造函數對對象進程初始化,它能夠爲對象在計算機內存中開闢內存空間,也能夠爲對象的數據成員提供初始值。構造函數時一個與類同名,沒有返回值的特殊成員函數,每當建立一個對象時(包括使用new動態建立對象),編譯系統就會自動調用構造函數。構造函數像類之外的通常函數和類成員函數同樣,能夠重載和帶缺省參數,構造函數的重載爲對象的生成提供了各類靈活的手段。ios

 構造函數分爲缺省構造函數(默認構造函數)和用戶自定義構造函數。當程序員沒有定義構造函數時,系統就會提供一個無參的缺省構造函數,若是用戶自定義了一個構造函數,編譯器提供的缺省構造函數就自動消失了。程序員


 

二、拷貝構造函數(複製構造函數)

拷貝構造函數的功能是一個已有的對象來初始化一個被建立的同類的對象,是一種特殊的構造函數,具備通常構造函數的全部特性,其形參是本類對象的引用。用戶能夠根據本身實際問題的須要定義特定的拷貝構造函數,以實現同類對象之間數據成員的傳遞。若是用戶沒有聲明類的拷貝構造函數,系統就會自動生成一個缺省拷貝構造函數,這個缺省拷貝構造函數的功能是把初始的每一個數據成員的值都複製到新創建的對象中。拷貝構造函數的聲明以下:編程

        類名(類型 & 對象名);數組

class people安全

{函數

public:學習

        void dipalay()this

        {spa

        }設計

private:

        int a;

        char*name;

};

調用拷貝構造函數有如下三種狀況:

(1)用類的一個對象去初始化另外一個對象時。

(2)對象做爲函數參數傳遞時,調用拷貝構造函數

(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

相關文章
相關標籤/搜索