在C++中,下面三种对象需要调用拷贝构造函数:
1) 一个对象以值传递的方式传入函数体;
2) 一个对象以值传递的方式从函数返回;
3) 一个对象需要通过另外一个对象进行初始化;
如果在前两种情况不使用拷贝构造函数的时候,就会导致一个指针指向已经被删除的内存空间。对于第三种情况来说,初始化和赋值的不同含义是构造函数调用的原因。事实上,拷贝构造函数是由普通构造函数和赋值操作符共同实现的。
例如:
int b = 6;
int a = b; // 拷贝构造函数
int a; // 构造函数
a = b; // 赋值操作符
什么时候需要重载拷贝构造函数和赋值操作符?
当用一个对象给另一个对象初始化,或将一个对象的值赋给另一个对象时,如果该对象的成员中含指针的时候,需要重载拷贝构造函数或赋值运算符。
例如,有一个类A:
class A
{
public:
A()
{
n = 0;
p = new int;
}
~A()
{
delete p;
}
private:
int n;
int *p;
};
当使用语句“A a; A b = a;”为b初始化时,将调用默认拷贝构造函数,相当于执行操作“b.n = a.n; b.p = a.p”,这将导致b.p指向的地址发生改变(指向了为a.p分配的内存)。在系统析构a、b时,便会发生有一块内存被释放两次,而另一块内存无法得到释放的问题。
解决方法就是重载A的拷贝构造函数:
A(A & a)
{
n = a.n;
p = new int;
*p = *(a.p);
}
这样只是把让b.p和a.p的值相等,而指向的地址不同,在析构的时候便不会出问题。
(注意:重载拷贝构造函数,必须先显式定义构造函数,否则,编译器会将拷贝构造函数误认为是构造函数,于是对象构造时调的是拷贝构造函数,而非系统默认的构造函数)
重载赋值运算符的情况与重载拷贝构造函数类似,只不过一个是发生在类对象的初始化,一个发生在对象的赋值。