effective C++ 读书笔记 条款12
条款12 : 复制对象时不要忘记其每一个成分
编写一个类用来表现顾客,其中手动写出copying函数使得外界对它们的调用记录会被logged下来:
#include <iostream> #include <string> using namespace std; void logCall(const string funcName) { cout<<funcName<<endl; } class Customer { public: Customer() { } Customer(const Customer& rhs); Customer& operator= (const Customer& rhs); private: string name; }; Customer::Customer(const Customer& rhs) { this->name = rhs.name; logCall("拷贝构造函数"); } Customer& Customer::operator=(const Customer& rhs) { logCall("赋值操作符重载"); name = rhs.name; return *this; } int main() { Customer c1; Customer c2(c1); Customer c3; c3 = c2; return 0; }
上面的函数看起来没有问题,知道一个新的成员变量加入:
#include <iostream> #include <string> using namespace std; void logCall(const string funcName) { cout<<funcName<<endl; } class Date { }; class Customer { public: Customer() { } Customer(const Customer& rhs); Customer& operator= (const Customer& rhs); private: string name; Date data; //这里增加一个成员变量 }; Customer::Customer(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 this->name = rhs.name; logCall("拷贝构造函数"); } Customer& Customer::operator=(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 logCall("赋值操作符重载"); name = rhs.name; return *this; } int main() { Customer c1; Customer c2(c1); Customer c3; c3 = c2; return 0; } /* 如果你为一个class添加一个成员变量,你必须同时修改copying函数,如果你忘记, 编译器是不会给出任何提示的。 */
上面说明:如果你为一个class添加一个成员变量,你必须同时修改copying函数
现在让他拥有子类:
#include <iostream> #include <string> using namespace std; void logCall(const string funcName) { cout<<funcName<<endl; } class Date { }; class Customer { public: Customer() { } Customer(const Customer& rhs); Customer& operator= (const Customer& rhs); private: string name; Date data; //这里增加一个成员变量 }; Customer::Customer(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 this->name = rhs.name; logCall("拷贝构造函数"); } Customer& Customer::operator=(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 logCall("赋值操作符重载"); name = rhs.name; 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& PriorityCustomer::operator =(const PriorityCustomer& rhs) { logCall("PriorityCustomer copy assignment operator"); priority = rhs.priority; return *this; } /* PriorityCustomer的copying函数看起来好像复制了PriorityCustomer内的每一样东西,但是仔细看就会发现, 它们复制了PriorityCustomer声明的成员变量,但是每个PriorityCustomer还内含它所继承的Customer成员变 量复件(副本),而这些成员变量却没有被复制。priorityCustome的copy构造函数并没有制定实参传给其base class构造函数(也就是说它在它的成员初值列表中没有提到Customer),因此PriorityCustomer对象的Customer 成分会被不带实参的Customer构造函数初始化,那么也就是说Customer内的成员变量name和data将执行缺省的初始化。 */ int main() { Customer c1; Customer c2(c1); Customer c3; c3 = c2; return 0; } /* */
子类的copy函数只是复制了子类本身加上去的成员变量,但是继承下来的成员变量却没有没复制,怎么解决?
#include <iostream> #include <string> using namespace std; void logCall(const string funcName) { cout<<funcName<<endl; } class Date { }; class Customer { public: Customer() { } Customer(const Customer& rhs); Customer& operator= (const Customer& rhs); private: string name; Date data; //这里增加一个成员变量 }; Customer::Customer(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 this->name = rhs.name; logCall("拷贝构造函数"); } Customer& Customer::operator=(const Customer& rhs) { //函数体并没有增加对data成员变量的处理,但是编译器不会给出任何警告 logCall("赋值操作符重载"); name = rhs.name; return *this; } /* 任何时候,只要我们为子类编写copy函数,那我们就必须小心复制其base class成分,而这些成分一般都是private; 所以我们无法直接访问他们,我们能做的就是让子类的copying函数调用相应的base class函数: */ class PriorityCustomer:public Customer { public: PriorityCustomer(const PriorityCustomer& rhs); PriorityCustomer& operator= (const PriorityCustomer& rhs); private: int priority; }; //我们能做的就是让子类的copying函数调用相应的base class函数: PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)//调用base class的copy构造函数 { logCall("PriorityCustomer copy constructor"); } //我们能做的就是让子类的copying函数调用相应的base class函数: PriorityCustomer& PriorityCustomer::operator =(const PriorityCustomer& rhs) { logCall("PriorityCustomer copy assignment operator"); Customer::operator =(rhs); //对base class成分进行赋值动作 priority = rhs.priority; return *this; } int main() { Customer c1; Customer c2(c1); Customer c3; c3 = c2; return 0; } /* */
我们能做的就是让子类的copying函数调用相应的base class函数
总结:
1:Copying函数应该确保复制“对象内的所有成员变量”及所有base class成分
2:不要尝试以某个copying函数实现另外一个copying函数。应该讲共同的机能放进第三个函数当中,并由两个copying函数共同调用。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。