Effective C++条款条款12:构造:构造/析构析构/赋值运算之(复制对象时勿忘其每一个成份)赋值运算之(复制对象时勿忘其每一个成份)
一、引入一、引入
我们在前面文章已经介绍了,如果类没有手动声明拷贝构造函数或拷贝赋值运算符,那么编译器会为我们自动生成这两个成员,并且它们的行为是:将被拷贝的将被拷贝的
对象的所有成员做一份拷贝对象的所有成员做一份拷贝
二、复制对象时确保复制所有成员二、复制对象时确保复制所有成员
下面的类有两个成员变量,因此我们需要为每一份成员进行一份复制为每一份成员进行一份复制
Customer::Customer(const Customer& rhs)
:name(rhs.name),lastTransaction(rhs.lastTransaction)
{
}
Customer& Customer::operator=(const Customer& rhs)
{
name = rhs.name;
lastTransaction = rhs.lastTransaction;
return *this;
}
三、有继承关系下的拷贝复制三、有继承关系下的拷贝复制
如果一个类拥有基类,那么在拷贝复制的时候不仅要复制派生类的部分,还要复制基类的部分不仅要复制派生类的部分,还要复制基类的部分
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
:Customer(rhs), //调用基类的拷贝构造函数
priority(rhs.priority)
{
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
Customer::operator=(rhs); //对基类部分进行赋值操作
priority = rhs.priority;
return *this;
}
四、避免在拷贝构造函数与四、避免在拷贝构造函数与operator=中进行互相调用中进行互相调用
我们可以看到拷贝构造函数和拷贝赋值运算符中都有相同的代码,并且完成相同的操作,但是我们不能为了简单化而在拷贝构造函数中调用拷贝赋值函数,或者在拷贝赋值函数中调用拷贝构造函数:但是我们不能为了简单化而在拷贝构造函数中调用拷贝赋值函数,或者在拷贝赋值函数中调用拷贝构造函数:
在拷贝赋值函数中调用拷贝构造函数是不合理的:在拷贝赋值函数中调用拷贝构造函数是不合理的:这就像在试图构造一个已经存在的对象
同理,在拷贝构造函数中调用拷贝赋值函数是不合理的:同理,在拷贝构造函数中调用拷贝赋值函数是不合理的:构造函数用来初始化新对象,而赋值运算符只用于已初始化对象身上,因此也是无意义的
建立函数解决上面的问题建立函数解决上面的问题
如果你认为拷贝构造函数与拷贝赋值运算符中代码有很多相似的代码,为了消除代码重复。可以建立一个新的成员函数供给两者调用
这样的函数一般都是private的,并且最好函数名以init开头
五、总结五、总结
拷贝函数应该确保复制“对象内的所有成员变量”及“所有基类成份”
不要尝试以某个拷贝函数实现另一个拷贝函数。应该将共同技能放进第三方函数,并由两个拷贝函数共同调用
作者:江南、董少