普通类型对象的拷贝
普通类型对象的拷贝很简单,就是值的复制而已。比如:
int _tmain(int argc, _TCHAR* argv[])
{
int a=1;
int b=a;
return 0;
}
类对象的拷贝
类对象的拷贝相比于普通类型的拷贝就复杂多了,它存在着各种成员变量。比如:
//CopyTest.h
class CCopyTest
{
public:
CCopyTest(int _size):size(_size){}
~CCopyTest(void){}
private:
int size;
};
//main.cppint _tmain(int argc, _TCHAR* argv[]){CCopyTest a(3),b=a;return 0;}
程序运行正常,b.size=3,看起来好像和普通类型数据也没什么差。好吧,继续往下看。
浅拷贝
我们再看一个例子。main.cpp和上面一样,CopyTest.h改为:
class CCopyTest
{
public:
CCopyTest(int _size):size(_size){data=new int[size];}
~CCopyTest(void){delete []data;}//这里进行了资源的释放
private:
int size;
int* data;
};
这时运行发现程序挂掉了,或者崩溃或者未响应。为什么呢?
原因:这时候浅拷贝的概念出来了。在将一个对象赋值给另外一个对象的时候,如果只是进行数据成员间值的简单拷贝,比如上面这个例子,b.size=a.size; b.data=a.data。注意,data可是个指针啊,那么此时a.data和b.data所指向的是同一块内存空间。对象a在虚构的时候,a.data所指向的堆内存被释放,这时再轮到对象b进行虚构,b.data所指向的堆内存再次要求被释放,就会出现问题。而例子2没有异常的原因是因为CopyTest这个类中没有指针等引用其他资源的对象,所以这时浅拷贝和深拷贝对它而言并没有区别。
深拷贝
深拷贝指的就是当拷贝对象中有对其他资源(如堆、文件、系统等)的引用时(引用可以是指针或引用)时,对象得另开辟一块新的资源,而不再对拷贝对象中有对其他资源的引用的指针或引用进行单纯的赋值,然后同步复拷贝开辟空间的值。
我们把上面的例子改一改。main.cpp不变,CopyTest.h更改为:
class CCopyTest
{
public:
CCopyTest(int _size):size(_size){data=new int[size];}
~CCopyTest(void){delete []data;}
CCopyTest(const CCopyTest& _copy):size(_copy.size){data=new int[size];memcpy(data,_copy.data,size);}//自定义拷贝构造函数
private:
int size;
int* data;
};
这里还要注意一点,拷贝构造函数必须采用引用传参的方式,而不能采用值传参,因为值传参本身就要进行值拷贝,调用拷贝构造函数会引起无限循环嵌套,编译器会报错,栈溢出。VS和GCC中都会报错。
总结
总之,在对进行对象拷贝时,当对象包含对其他资源的引用,如果需要拷贝这个对象所引用的对象,那就是深拷贝,否则即是浅拷贝。