#include <bits/stdc++.h>
#include <iostream>
using namespace std;
class A
{
private:
int *p;
public:
A()
{
}
int * ini()
{
p = new int[8];
p[0] = 12;
return p;
}
int show()
{
cout << p[0] << endl;
return 0;
}
~A()
{
delete[] p;
}
};
int main(){
A a2;
{
A a1;
a1.ini();
a1.show();
a2 = a1;
}
a2.show();
return 0;
}
上图是代码的运行结果,为什么两次的p[0]结果不一样呢?而且第二次的p[0]的值是一个随机数。
其实熟悉c++的同学已经发现了,这是由于浅拷贝的原因造成的,改正的方法就是换成深拷贝,重载赋值运算符。
那么什么是浅拷贝和深拷贝呢?
就用上述代码 作为例子,我们可以看到类中有一个指针变量的成员p,且该指针指向堆上分配的空间。当我们在做对象之间的赋值时,就会调用默认的赋值运算符,然而默认的赋值运算符是一个浅拷贝,浅拷贝只是让被赋值的对象中的p和赋值对象中的p指向了同一片区域(即a2.p = a1.p),然而赋值对象在析构时就把p指向的区域释放掉了,所以第二次输出的p[0]就是一个随机数,而不是12。
那么深拷贝是如何解决这个问题的呢?
其实很简单,我们在重载赋值运算符时重新开辟一段区域,并把复制对象中对应的区域复制过来,并把p指向这个区域,这样就是一个深拷贝的过程,即使原来的区域被释放掉,任然可以输出12,从而达到我们的预期目的。具体代码如下:
A & operator = (A & a)
{
p = new int[8];
memcpy(p, a.p, sizeof(p));//深拷贝
return *this;
}
除了a2 = a1这种赋值形式,还有一种情况 A a2 = a1这种赋值形式,而这种赋值形式就不是调用赋值运算符了,而是调用拷贝构造函数,那么相应的就是把深拷贝做到拷贝构造函数里了。
总结:一般,如果需要手动编写析构函数的类,都需要overload 拷贝构造函数和赋值运算符。