(一)拷贝构造函数

同一个类的对象在内存中拥有相同的结构,若作为整体拷贝是可以的。但我们知道,同一个类的方法是所有该类的对象共用的。所以只需要拷贝数据成员。拷贝构造函数的功能就是专门拷贝数据成员的函数。

拷贝构造函数的作用:当使用一个成员对象初始化一个对象时,会调用该函数来构造对象


(二)浅拷贝的问题

- 当析构使用缺省的拷贝构造函数(浅拷贝)构造的对象和被拷贝的对象时(有堆区空间),在两次delete时,由于是浅拷贝,所以两次delete的空间地址是同一块内存地址,程序会崩溃。

(三)解决方案

(1)深拷贝的拷贝构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Object
{
public:
//深拷贝拷贝构造函数
Object(const Object& src):name(new char[strlen(src.name) + 1])
{
//深拷贝
strcpy(name, src.name);
}
//对应的析构函数
~object()
{
if(name != NULL)
{
delete[] name;
}
}
private:
char* name;
};

(2)引用计数技术

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
class Object
{
public:
Object()
:name(new char[1]),count(1);
{
*name = '\0';
}
//浅拷贝的拷贝构造函数
Object(Object& src)
{
//浅拷贝,引用计数
src.count++;
*this = src; //使用默认的赋值运算符重载函数
}
//析构函数
~Object()
{
if(count == 1)
{
delete[] name;
count = 0;
}
else
{
//引用计数-1
count--;
}

}
private:
char* name;
int count;
};


(四)总结

  • 拷贝构造函数的参数一定要使用引用(值传递会造成无限递归,因值传递生成临时对象需要调用拷贝构造函数…)
  • 当没有显示指定该类的拷贝构造函数时,编译器提供缺省的拷贝构造函数(浅拷贝)
    形如:
1
2
3
4
5
6
7
8
9
class Object
{
public:
//缺省拷贝构造函数
Object(const Object& src):name(src.name)
{}
private:
char* name;
};
  • 当函数的返回值是类的对象,返回的对象其实是一个通过拷贝构造函数构造的临时对象。(函数返回结束,函数栈帧回收,栈帧中的对象已无效),所以在返回之前会调用拷贝构造函数生成临时对象并返回。当该句函数调用完成,该临时对象会被析构。