複製構造函數也叫拷貝構造函數;
淺複製也叫淺拷貝或位拷貝;
深複製也叫深拷貝;
淺拷貝和深拷貝
拷貝就是複製,創建副本。假設有對象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;
//20200430 歡迎關注公衆號:C語言與CPP編程
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;
}
根據上面實例可以看到,淺複製僅複製對象本身(其中包括是指針的成員),這樣不同被複制對象的成員中的對應非空指針會指向同一對象,被成員指針引用的對象成爲共享的,無法直接通過指針成員安全地刪除(因爲若直接刪除,另外對象中的指針就會無效,形成所謂的野指針,而訪問無效指針是危險的;除非這些指針有引用計數或者其它手段確保被指對象的所有權);而深複製在淺複製的基礎上,連同指針指向的對象也一起復制,代價比較高,但是相對容易管理。