設計良好的面向對象系統會將對象的內部封裝起來,只留兩個函數負責對象拷貝,即copy構造函數與copy assignment操做符。編譯器會在必要的時候爲類建立coping函數,並說明這些「編譯器生成版」的行爲:將被拷貝對象的全部成員變量都作一份拷貝。安全
任什麼時候候,只要本身實現派生類的copying函數,則必須很當心的複製其基類成分。這些成分每每是private私有的,故沒法直接訪問它們,所以應該讓派送類的coping函數調用相應的基類函數:函數
void logCall(const string& funcName);
class Customer { public:
... Customer(const Customer& rhs); Customer& operator=(const Customer& rhs);
... private: string name; Date lastTranscation; };
class PriorityCustomer : public Customer { public: ... PriorityCustomer(const PriorityCustomer& rhs); PriorityCustomer& operator=(const PriorityCustomer& rhs); ... private: int priority; }; PriorityCustomer ::PriorityCustomer (const PriorityCustomer& rhs) : Customer(rhs), //調用基類的copy構造函數 priority(rhs.priority) { logCall("PriorityCustomer copy constructor"); } PriorityCustomer& PriorityCustomer ::operator = (const PriorityCustomer& rhs) { logCall("PriorityCustomer copy assignment constructor"); Customer::operator=(rhs); //對基類Customer成分進行復制動做 priority = rhs.priority; return *this; }
當編寫一個copying函數,確保一、複製全部local成員變量,二、調用全部基類的適當的copying函數。this
注意兩個錯誤用法:一、令copy assignment操做符調用copy構造函數是錯誤的,由於在這就像試圖構造一個已存在的對象。spa
二、令copy構造函數調用copy assignment操做符一樣是錯誤的。構造函數用來出過後對象,而assignment操做符只實行與已初始化的對象身上。對一個還沒有構造好的對象賦值,就像在一個還沒有初始化的對象身上作「z只對已初始化對象纔有意義」的事意義。設計
消除copy構造函數與copy assignment操做符重複代碼的作法是:創建一個新的成員函數給二者調用。這樣的函數每每是private並且被命名爲init。這個策略能夠安全消除copy構造函數與copy assignment操做符之間的代碼重複。對象
請牢記:blog
一、copying 函數應該確保複製「對象內的全部成員變量」及「全部基類成分」。編譯器
二、不要嘗試以某個copying函數實現另外一個copying函數。應該將共同機能放進第三個函數中,並由兩個copying函數共同調用。string