淺拷貝:只是將值原樣賦值給新的對象中的成員變量。如果類中涉及到內存動態分配就會出錯
深拷貝:先開闢空間,然後再賦值
默認的拷貝構造函數是淺拷貝,只是逐個賦值
先看一個例子,觀察淺拷貝能出現什麼問題:
#include <iostream>
#include <string.h>
using namespace std;
class String
{
private:
char *str_;
public:
String(char *str="")
{
int len = strlen(str)+1;
str_ = new char[len];
memset(str_,0,len); //將str_內存地址的前len個位置設置爲0
strcpy(str_,str);
}
~String()
{
delete []str_;
}
void display()
{
cout<<str_<<endl;
}
};
int main()
{
String s("ABC");
s.display();
//String s2 = s; //調用的是默認的拷貝構造函數,實施的是淺拷貝
//等價於s2.str_ = s.str_ 逐個賦值
//兩者指向同一個內存,在程序退出時調用析構函數,同一塊內存被釋放了兩次,因此出錯
return 0;
}
對上述的問題解決方案:重寫拷貝構造函數,使其指向兩個不同的內存空間
代碼如下:
String(const String &other)
{
int len = strlen(other.str_)+1;
str_ = new char[len];
memset(str_,0,len);
strcpy(str_,other.str_);
}
接下來看下面代碼是怎麼執行的:
String s3;
//s3 = s; //error 調用的是=運算符,系統提供的默認等號運算符也是淺拷貝
解決方案就是重寫=運算符:
String &operator=(const String &other)
{
if(this == &other)
{
return *this;
}
//否則的話就銷燬以前已經存在的空間
delete[] str_;
int len = strlen(other.str_)+1;
str_ = new char[len];
memset(str_,0,len);
strcpy(str_,other.str_);
}
這裏這是爲了介紹深拷貝與淺拷貝,其實最終的問題是出在析構函數中的delete處,可以根據自己的需要來修改。
有些對象是唯一的獨一無二的,是不能拷貝和賦值的,可以將拷貝構造函數和=運算符函數放到私有函數中,並且不提供實現(不提供實現是爲了只要調用這兩個函數時在編譯階段就會報錯)。達到禁止拷貝的效果。