問題聚焦:
負責拷貝的兩個操作:拷貝構造函數和重載賦值操作符。 一句話總結,確保被拷貝對象的所有成員變量都做一份拷貝。
void logCall(const std::string& funcName); // log函數 class Date{ ... }; class Customer { public: .... Customer(const Customer& rhs); Customer& operator=(const Customer& rhs); private: std::string name; Date lastTransaction; }; Customer::Customer(const Customer& rhs) : name(rhs.name) // 忽略了lastTransaction成員變量 { logCall("Customer copy constructor"); } Customer& Customer::operato=(const Customer& rhs) { logCall("Customer copy assignment operator"); name = rhs.name; // 忽略了lastTransaction成員變量 return *this; }
class PriorityCustomer: public Custoer { public: ... PriorityCustomer(const PriorityCustoer& rhs); PriorityCustomer& operato=(const PriorityCustomer& rhs); ... private: int priority; }; PriorityCustomer& PriorityCustomer::PriorityCustomer (const PriorityCustomer& rhs) : priority(rhs.priority) { logCall("PriorityCustoer copy constructor"); } PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs) { logCall("PriorityCustomer copy assignment operator"); priority = rhs.priority; return *this; }
PriorityCustomer的拷貝函數們拷貝了它聲明的成員變量,卻忽略了它所繼承的Customer成員變量的拷貝,也沒有指定實參傳遞給Customer的構造函數,因此,PriorityCustomer對象的Customer成分會被不帶實參的Customer默認構造函數初始化。
PriorityCustomer& PriorityCustomer::PriorityCustomer (const PriorityCustomer& rhs) : Customer(rsh), priority(rhs.priority) { logCall("PriorityCustoer copy constructor"); } PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs) { logCall("PriorityCustomer copy assignment operator"); Customer::operator=(rhs); priority = rhs.priority; return *this; }
確保賦值所有local成員變量
調用所有base classes內的適當的拷貝函數
雖然重載賦值操作符和拷貝函數的代碼長得很像,但是很難復用它們,因為重載賦值操作符時調用拷貝構造函數就像在構造一個已經存在的對象; 同樣地,令拷貝構造函數調用重載賦值操作符一樣沒有意義。所以,復用這兩個代碼的方式就是寫一個新的成員函數給兩者調用。
拷貝構造函數和重載賦值操作符應該確保復制“對象內的所有成員變量”及“所有base class成分”; 不要嘗試拷貝構造函數調用重載賦值操作符或是反過來。