1. 拷贝构造(赋值)函数应该确保复制“对象内的所有成员变量”及“所有 base class 成分”。
2. 不要尝试以某个拷贝函数实现另一个拷贝函数。应该将共同机能放进第三个函数中,并由两个拷贝函数共同调用。例如,创建一个 private 的初始化函数而且常被命名为init,可消除拷贝构造和拷贝赋值操作符之间的代码重复。
void logCall(const std::string& funcName); // 记录日志
class Customer {
public:
...
Customer(const Custoer& rhs);
Customer& operator=(const Customer& rhs);
...
private:
std::string name;
};
Customer::Customer(const Customer& rhs)
: name(rhs.name) // 复制rhs的数据
{
logCall("Customer copy constructor");
}
Customer& Customer::operator=(const Customer& rhs)
{
logCall("Customer copy assignment operator");
name = rhs.name; // 复制rhs的数据
return *this;
}
// 一个派生类
class PriorityCustomer: public Customer {
public:
...
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator=(const PriorityCustomer& rhs);
...
private:
int priority;
};
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: priority(rhs.priority)
{
logCall("PriorityCustomer copy constructor");
}
PriorityCustomer& PriorityCustoer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
priority = rhs.priority;
return *this;
}
PriorityCustomer 的 拷贝构造(赋值)函数看起来好像复制了 PriorityCustomer 内的每一个它声明的成员变量,但每个 PriorityCustomer 还内含它所继承的 Customer 成员变量副本,而那些成员变量却未被复制。
PriorityCustomer 的 拷贝构造函数并没有指定实参传给其 base class 构造函数(也就是说它在它的成员初值列中没有提到 customer),因此 PriorityCustomer 对象的 customer 成分会被不带实参的 Customer 构造函数(即默认构造函数)初始化。默认构造函数将针对 name 和 lastTransaction 执行缺省的初始化动作。
在拷贝赋值操作符上只有轻微不同。它不曾企图修改其 base class 的成员变量,所以那些成员变量保持不变。
正确的做法是,让 derived class 的拷贝构造(赋值)函数调用相应的 base class 函数:
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs)
: Customer(rhs), // 调用基类的拷贝构造函数
priority(rhs.priority)
{
logCall("PriorityCustomer copy constructor");
}
PriorityCustomer& PriorityCustoer::operator=(const PriorityCustomer& rhs)
{
logCall("PriorityCustomer copy assignment operator");
Customer::operator=(rhs); // 对基类成分进行赋值动作
priority = rhs.priority;
return *this;
}
评论区