相关知识:
- 类中如果不自己定义默认拷贝函数,即系统自动生成的默认拷贝函数实现的默认的拷贝行为是浅拷贝。
- 对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
- 下面代码中我们显式地定义了拷贝构造函数,它除了会将原有对象的所有成员变量拷贝给新对象,还会为新对象再分配一块内存,并将原有对象所持有的内存也拷贝过来。这样做的结果是,原有对象和新对象所持有的动态内存是相互独立的,更改一个对象的数据不会影响另外一个对象。这种将对象所持有的其它资源一并拷贝的行为叫做深拷贝,我们必须显式地定义拷贝构造函数才能达到深拷贝的目的。
什么时候需要深拷贝?
- 如果一个类拥有指针类型的成员变量,那么绝大部分情况下就需要深拷贝,因为只有这样,才能将指针指向的内容再复制出一份来,让原有对象和新生对象相互独立,彼此之间不受影响。如果类的成员变量没有指针,一般浅拷贝足以。
- 另外一种需要深拷贝的情况就是在创建对象时进行一些预处理工作,比如统计创建过的对象的数目、记录对象创建的时间等。
深复制和浅复制实现的效果图:
代码涉及内容:
- 复制构造函数/拷贝构造函数
- 浅复制/浅拷贝/位拷贝
- 深复制/深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54#include <iostream>
#include <cstring>
#include <string.h>
using namespace std;
class CDemo
{
public:
CDemo(int pa, const char *cstr) // 注意此处要加 const,否则会有错误:C2664...
{
this->a = pa;
// 因为第二个数据成员是指针,所以需要用new操作符动态的在堆上分配存储空间,然后把指针传进来的字符串用strcpy_s()进行拷贝;
this->str = new char[1024];
strcpy_s(this->str,1024, cstr);
}
// 如果自己不写c++会自动生成一个复制构造函数,实现的是浅复制;
CDemo(CDemo& obj)
{
this->a = obj.a;
// this->str = obj.str; // 这是浅复制;如果不自己写构造函数,系统自动生成的构造函数就是这种效果,实现的是浅复制;
this->str = new char[1024];
if (str != 0)
strcpy_s(this->str, 1024, obj.str);
}
~CDemo()
{
delete str; // 用new创建之后要在此处delete进行删除;
}
public:
int a;
char *str;
};
int main()
{
CDemo A(10,"hello");
cout << A.a << ", " << A.str << endl;
CDemo B = A; // 复制;
cout << "A: " << A.a << ", " << A.str << endl;
cout << "B: " << B.a << ", " << B.str << endl;
B.a = 3;
B.str[0] = 'k';
cout << "修改后: " << endl;
cout << "A: " << A.a << ", " << A.str << endl;
cout << "B: " << B.a << ", " << B.str << endl;
return 0;
}默认复制构造函数实现的结果(浅复制):
上面程序运行结果(深复制):
参考链接:
C++深拷贝和浅拷贝(深复制和浅复制)完全攻略