C++中为啥要定义拷贝构造函数和拷贝赋值运算符
类对象给类对象赋值时,要用拷贝构造函数。
对一个简单变量的初始化方法是用一个常量或变量初始化另一个变量,例如:
int m = 80;
int n = m;
我们已经会用构造函数初始化对象,那么我们能不能象简单变量的初始化一样,直接用一个对象来初始化另一个对象呢?答案是肯定的。以一个Point类为例:
Point pt1(15, 25);
Point pt2 = pt1;
后一个语句也可以写成:
Point pt2( pt1);
它是用pt1初始化pt2,此时,pt2各个成员的值与pt1各个成员的值相同,也就是说,pt1各个成员的值被复制到pt2相应的成员当中。在这个初始化过程当中,实际上调用了一个复制构造函数。当我们没有显式定义一个复制构造函数时,编译器会隐式定义一个缺省的复制构造函数,它是一个内联的、公有的成员,它具有下面的原型形式:
Point:: Point (const Point &);
可见,复制构造函数与构造函数的不同之处在于形参,前者的形参是Point对象的引用,其功能是将一个对象的每一个成员复制到另一个对象对应的成员当中。
虽然没有必要,我们也可以为Point类显式定义一个复制构造函数:
Point:: Point (const Point &pt)
{
xVal=pt. xVal;
yVal=pt. yVal;
}
如果一个类中有指针成员,使用缺省的复制构造函数初始化对象就会出现问题。为了说明存在的问题,我们假定对象A与对象B是相同的类,有一个指针成员,指向对象C。当用对象B初始化对象A时,缺省的复制构造函数将B中每一个成员的值复制到A的对应的成员当中,但并没有复制对象C。也就是说,对象A和对象B中的指针成员均指向对象C。
当类中没有指针类型的数据成员时可以通过调用默认的构造函数就可以,而类中有指针类型的数据成员时,就要调用自己写的拷贝构造函数,以避免指针所指向的内存被释放两次(是按位拷贝,所以两个对象指针所指向相同的内存,当对象被销毁时,会调用各自的析构函数,这样也就把这块内存释放了两次,引发错误)。
区分拷贝构造函数和拷贝赋值运算符,要能区分初始化和赋值:
classA {};
A a1;
A a2 = a1;//同类对象初始化,调用复制构造
A a3;
a3 = a1;//赋值,调用=号重载的函数