Effective C++ 条款12_不止于此

复制对象时勿忘其每一个成分

设计良好之面向对象系统会将对象的内部封装起来,只留两个函数负责对象拷贝(copy 构造函数和 copy assignment 操作符)
在 C++ 中,如果自己声明 copying 函数,会发生这样一种情况:当你的实现代码几乎必然出错时却不告诉你。
看下面的代码说事:

void logCall(const std::string& funcName);  // 制造一个 log entry
class Customer {
    
    
public:
	...
	Customer(const Customer& r);
	Customer& operator=(const Customer& r);
	...
private:
	std::string name;
	};
Customer::Customer(const Customer& r): name(r.name){
    
       // 复制 r 的数据
	logCall("Customer copy constructor");
	}
Customer& Customer::operator=(const Customer& r){
    
    
	logCall("Customer copy assignment operator");
	name = r.name;			// 复制 r 的数据
	return *this;
	}

这样做看起来很好,实际也很好,但如果另一个变量的加入就会打破这个美好的局面:

class Date {
    
    ...};			// 日期
class Customer {
    
    
public:
	...
private:
	std::string name;
	Date lastTransaction;
	}

这时候上面的 copying 函数执行的就是局部构造:
复制了 name,但是没有复制新添加的 lastTransaction。但大多数的编译器都不会报错。

一但发生继承,将面临这一主题最暗中肆虐的危机:

class vipCustomer: public Customer {
    
      	// 一个 derived class
public: 
	...
	vipCustomer(const vipCustomer& r);
	vipCustomer& operator=(const vipCustomer& r);
private:
	 int vip;
	};

vipCustomer::Customer(const vipCustomer& r): vip(r.vip){
    
       // 复制 r 的数据
	logCall("vipCustomer copy constructor");
	}
vipCustomer& vipCustomer::operator=(const vipCustomer& r){
    
    
	logCall("vipCustomer copy assignment operator");
	vip = r.vip;			// 复制 r 的数据
	return *this;
	}

vipCustomer 的 copying 函数只是复制了 vipCustomer 声明的成员变量,但是它还含有从 base class 继承的成员变量附件(副本),但没有被复制。因此 base class 的成员变量保持不变。

在为 derived class 撰写 copying 函数时,都必须小心地也复制其 base class 的成分。那些成分往往是 private 的,所以应该让 derived class 的 copying 函数调用相应的 base class 函数:

vipCustomer::Customer(const vipCustomer& r): 
	Customer(r);	// 调用 base class 的 copy 构造函数
	vip(r.vip){
    
       // 复制 r 的数据
	logCall("vipCustomer copy constructor");
	}
vipCustomer& vipCustomer::operator=(const vipCustomer& r){
    
    
	logCall("vipCustomer copy assignment operator");
	Customer::operator(r);   // 对 base class 成分进行赋值操作
	vip = r.vip;			// 复制 r 的数据
	return *this;
	}

上面只是简单介绍,详细内容会在条款22细说。
copy 构造函数和 copy assignment 操作符不能相互调用!

最后记住:

  • Copying 函数应该确保复制 “ 对象内的所有成员变量 ” 及 “ 所有 base class 成分 ”。
  • 不要尝试以某个 copying 函数实现另一个 copying 函数。应该将共同机能放进第三个函数中,并由两个 copying 函数共同调用。

猜你喜欢

转载自blog.csdn.net/weixin_48033173/article/details/109048560