【effective c++】 条款12:复制对象时勿忘其每一个成分

来源:互联网 发布:mysqldump 导出表数据 编辑:程序博客网 时间:2024/05/02 08:41

设计良好的面向对象系统会将对象的内部封装起来,指留下两个函数负责对象拷贝,那便是带着适切名称的copy构造函数和copy assignment操作符,我们称它们为copying函数。

考虑一个类用来表示顾客,手工写出copying函数:

  1. void logCall(const std::string& funName);//构造一个log entry  
  2. class Customer  
  3. {  
  4. public:  
  5.   ...  
  6.   Customer(const Customer& rhs);  
  7.   Customer& operator=(const Customer& rhs);  
  8.   ...  
  9. private:  
  10.   std::string name;  
  11. }; 
  12. Customer::CUstomer(const Customer& rhs):name(rhs.name) 
  13.   logCall("Customer copy constructor"); 
  14. Customer& Customer::operator=(const Customer& rhs) 
  15.   logCall("Customer copy assignment operator"); 
  16.   name = rhs.name; 
  17.   return *this

以上是正确的。

假如加入数据:

  1. class Date{...};//日期 
  2. class Customer 
  3. public
  4.   ... //同前 
  5. private
  6.   std::string name; 
  7.   Date lastTransaction; 
  8. }; 

这时候copying执行的是局部拷贝:它们的确复制了顾客的name,但是没有赋值新添加到lastTransaction,大多数编译器对此不出任何警告。如果你为class添加了一个成员变量,你必须同时修改copying函数。

如果继承,可能会造成一个潜在危机:

  1. class PrioCustomer:public Customer 
  2. public
  3.   ... 
  4.   PrioCustomer(const PrioCustomer& rhs); 
  5.   PrioCustomer& operator=(const PrioCustomer& rhs); 
  6.   ... 
  7. private
  8.   int prio; 
  9. }; 
  10. PrioCustomer::PrioCustomer(const PrioCustomer& rhs):prio(rhs.prio) 
  11.   logCall("PrioCustomer copy constructor"); 
  12. PrioCustomer& PrioCustomer::operator=(const PrioCustomer& rhs) 
  13.   logCall("PrioCustomer copy assignment operator"); 
  14.   prio = rhs.prio; 
  15.   return *this

看起来好像是复制了PrioCustomer内的每一个数据,但每个PrioCustomer还内含它所继承的Customer成员变量,而那些变量却未被赋值。

应该让继承类的copying函数调用相应的基类函数:

  1. PrioCustomer::PrioCustomer(const PrioCustomer& rhs) 
  2.  :Customer(rhs),prio(rhs.prio) 
  3.   logCall("PrioCustomer copy constructor"); 
  4. PrioCustomer& PrioCustomer::operator=(const PrioCustomer& rhs) 
  5.   logCall("PrioCustomer copy assignment operator"); 
  6.   Customer::operator=(rhs); 
  7.   prio = rhs.prio; 
  8.   return *this

 当你编写一个copying函数,请确保:复制所有local成员变量,调用所有基类内的适当的copying函数。

令copy assignment操作符调用copy构造函数是不合理的。

令copy构造函数调用copy assignment操作符也是不合理的。

如果你发现你的copy构造函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数给两者调用,这样的函数往往是private而且常被命名为init。

 

1.Copying函数应该确保复制“对象内的所有成员变量”及“所有基类成分”

2.不要尝试以某个copying函数实现另一个copying函数,应该将共同机能放在第三个函数中,并由两个copying函数共同调用。

 


原创粉丝点击