copy 函数
设计良好之面向对象系统会将对象的内部封装起来,只留两个函数负责对象拷贝(复制),copy构造函数和co培养assignment 操作符。
如果你声明自己的copying函数,意思是告诉编译器你并不喜欢缺省实现中的某些行为。编译器会以一种奇怪的方式回敬:当你的实现代码几乎必然出错却不告诉你。
void logCall(const std::string& funcName); class Customer{ public : ... Customer(const Customer&rhs); Customer& operator=(const Customer &rhs); ... private: std::string name; }; Customer::Customer(const Customer &rhs):name (rhs.name) { logCall("Customer copy constructor"); } Customer &Customer::operator=(const Customer&rhs) { logCall("Customer copy assignment operator"); name = rhs.name; return *this; }
如果另一个成员变量加入战局class Date{...}; class Customer{ public: ... //同前 private: std::string name; Date lastTransaction; }
这时既有的copying函数执行的是局部拷贝:复制了name,没有新添加复制的lastTransaction。编译器不会发生怨言。
如果你为class添加一个变量,你必须同时修改copy函数(还有class内所有构造函数以及任何非标准形式的operator=)
一旦发生继承
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还内涵它所继承的Customer成员变量复件(副本),而那些成员变量并未复制。PriorityCustomer的copy构造函数并没有指定的实参传给base class构造函数(也就是说它在它的成员初值列中没有提到Customer),因此PriorityCustomer对象Customer成分会被不带实参之Customer构造函数(即default构造函数)初始化。default构造函数将针对name和lastTransaction执行缺省的初始化动作。
任何时候需要“为derived class 撰写copying函数”的重责大任,必须复制其base class 成分。应该用derived class 的copying函数调用相应的base class函数。
当编写一个copying函数,请确保 (1)复制所有local成员变量 (2)调用所有base class 内的适当的copying函数PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority) { logCall("PriorityCustomer copy constructor"); } PriorityCustomer&PriorityCustomer::operator=(const PriorityCustomer &rhs) { logCall("PriorityCustomer copy assignment operator"); Customer::operator=(rhs); priority = rhs.priority; return *this; }
如果copy函数和copy assignment操作符有相近的代码,消除重复代码的做法是,建立一个新的成员函数给两者调用。这样的函数往往是private而且常被命名为init.
Copying函数应该确保复制“对象内所有成员变量”及“所有base class”成分。
不要尝试以某个copy函数实现另一个copy函数。应该将共同机能放进第三个函数中,并由两个coping函数共同调用。