条款12:复制对象时勿忘其每一个成分

设计良好的OO系统会将对象的内部封装起来,只留两个函数负责对象拷贝,那便是copy构造函数和copy assignment操作符。

         我们知道,如果不给类提供一个copy函数,则当需要时,编译器会为我们提供copy函数。

         但是,如果你自己声明了copy函数,就是在拒绝了编译器为你提供的版本。意思是你不喜欢编译器所提供的版本,此时,如果它好像是被冒犯了一样,如果你的代码出现了错误,它也不提醒你。

classCustomer{

...

    Customer(constCustomer&rhs);

    Customer&operator=(constCustomer&rhs);

...

private:

    std::stringname;    

};

 

Customer::Customer(constCustomer&rhs):name(rhs.name){ }

Customer::operator=(constCustomer&rhs){

    name=rhs.name;

    return*this;

}

我们忽略第10条款所讲的内容,这是一个很好的程序,但是当我们的class发生变化时,灾难来了。比如我们的class加入一个新的数据成员:

classDate{};

classCustomer{

...

  Customer(constCustomer&rhs);

  Customer&operator=(constCustomer&rhs);

...

private:

  std::stringname;    

  DatelastTransaction

};

而我们忽略了copy函数的修改,灾难就来了。因为,我们只对Customer对象的局部数据成员(name)进行了复制,而对lastTransaction成员没有操作,所以会使此数据成员未被初始化。

classPriorityCustomer:publicCustomer{

public:

  PriorityCustomer(constPriorityCustomer&rhs);

  PriorityCustomer&operator=(constPriorityCustomer&rhs);

private:

  intpriority;

};

 

PriorityCustomer::PriorityCustomer(constPriorityCustomer&rhs):priority(rhs.priority){}

PriorityCustomer&PriorityCustomer::operator=(constPriorityCustomer&rhs){

  this->priority=rhs.priority;

  return*this;

}

你会发现,此时的copy函数并没有对基类成员的初始化。因此隐式地会调用基类的无参的默认的构造函数,也就导致了基类局部成员的未初始化。为了避免此灾难,我们要显式的对基类成员进行初始化工作。

 

PriorityCustomer::PriorityCustomer(constPriorityCustomer&rhs):priority(rhs.priority),Customer(rhs){}

PriorityCustomer&PriorityCustomer::operator=(constPriorityCustomer&rhs){

    Customer::operator=(rhs);

    this->priority=rhs.priority;

    return*this;

}

因此,当你编写一个copy函数时,请确保:

1)     复制所有的local成员变量

2)     调用所有base classes内的适当的copying函数。

注意以下两点:

1)   令赋值操作符调用拷贝构造函数是不合理的。

2)   令拷贝构造函数调用赋值操作符也是不合理的。

如果你发现你的赋值操作符与拷贝构造函数有太多的相似代码,消除重复的方法是,建立一个新的成员函数供它们调用。这样的函数往往是private而且常命名为init。

请记住:

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

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

原文地址:https://www.cnblogs.com/loveyakamoz/p/2772387.html