Effective C++_笔记_条款12_复制对象时勿忘其每一个成分

(整理自Effctive C++,转载请注明。整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 

 

    编译器会在必要时候为我们的classes创建copying函数,这些“编译器生成版”的行为:将被烤对象的所有成员变量都做一份拷贝。

    如果你声明自己的copying函数,意思就是告诉编译器你并不喜欢缺省实现中的某些行为。编译器仿佛被冒犯似的,会以一种奇怪的方式回敬:当你的实现代码几乎必然出错时却不告诉你。所以自己实现copying函数时,请遵循一条规则:如果你为class添加一个成员变量,你必须同时修改copying函数(你也需要修改class的所有构造函数以及任何非标准形式的operator=)。如果你忘记,编译器不太可能提醒你。

    但是也要注意,一旦发生继承,可能会造成此一主题最暗中肆虐的一个潜藏危机。试考虑:

 

   1: class PriorityCustomer:public Customer{
   2: public:
   3:     ...
   4:     PriorityCustomer( const PriorityCustomer& rhs) ;
   5:     PriorityCustomer& operator=( const PriorityCustomer& rhs ) ;
   6:     ...
   7: private:
   8:     int priority ;
   9: };
  10:  
  11: PriorityCustomer::PriorityCustomer( const PriorityCustomer& rhs )
  12:   :priority(rhs.priority)
  13: {
  14:     logCall("PriorityCustomer copy constructor" ) ;
  15: }
  16:  
  17: PriorityCustomer& PriorityCustomer::operator= ( const PriorityCustomer& rhs )
  18: {
  19:     logCall("PriorityCustomer copy assignment operator ");
  20:     priority = rhs.priority ;
  21:     return *this ;
  22: }

 

 

    我们可以看到,PriorityCustomer的copying函数看起来好像复制了PriorityCustomer的每一样东西。是的,它们复制了PriorityCustomer声明的成员变量,但每个PriorityCustomer还内含它所继承的Customer成员变量复件,而那些成员变量却未被复制。PriorityCustomer的copy构造函数并没有指定实参传给其base class构造函数,因此PriorityCustomer对象的Customer成分会被不带实参之Customer构造函数(即default构造函数---必定有一个否则无法通过编译)初始化。default构造函数对base class 成分执行缺省的初始化动作。

    以上事态在PriorityCustomer的copy assignment操作符身上只有轻微不同。它不曾企图修改其base class的成员变量,所以那些成员变量保持不变。

    任何时候只要你担负起“为derived class撰写copying函数”的重大责任,必须很小心地赋值其base class成分。那些成分往往是private,所以你无法直接访问它们,你应该让derived class的copying函数调用相应的base class函数:

 

   1: PriorityCustomer:PriorityCustomer( const PriorityCustomer& rhs )
   2:     :Customer(rhs),                //调用base class的copy构造函数
   3:      priority(rhs.priority)
   4: {
   5:     logCall( "PriorityCustomer copy constructor " ) ;
   6: }
   7:  
   8: PriorityCustomer&
   9: PriorityCustomer::operator=( const PriorityCustomer& rhs )
  10: {
  11:     logCall("PriorityCustomer copy assignment operator") ;
  12:     Customer::operator=(rhs) ;     //对base class成分进行赋值动作
  13:     priority = rhs.priority ;
  14:     return *this ;
  15: }

 

    本条款题目所说的“复制每一个成分”现在应该说的很清楚了。当你编写一个copying函数,请确保(1)复制所有local成员变量,(2)调用所有base class内适当的copying函数。

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

    不要令某个copying函数调用另一个copying函数:令copy assignment操作符调用copy构造函数是不合理的,因为这试图构造一个已经存在的对象。反方向—令copy构造函数调用copy assignment操作符—同样无意义。构造函数用来初始化新对象,而assignment操作符只施行于已初始化对象身上。

 

    请记住:

(1)Copying函数应该确保复制“对象内的所有的成员变量”及“所有base class成分”。

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

posted @ 2014-06-29 09:42  华科小涛  阅读(255)  评论(0编辑  收藏  举报