設計良好的面向對象系統將對象內部封裝,僅暴露拷貝構造函數與拷貝賦值運算符(統稱 copying 函數)供外部複製對象。編譯器合成版本會逐一拷貝所有非靜態成員變量;若自行聲明,必須確保:
基類成員多為 private,派生類無法直接訪問。必須在派生類的 copying 函數中顯式調用基類對應函數:
class Customer {
string name;
public:
Customer(const Customer& rhs) : name(rhs.name) {}
Customer& operator=(const Customer& rhs) {
name = rhs.name;
return *this;
}
};
class PriorityCustomer : public Customer {
int priority;
public:
PriorityCustomer(const PriorityCustomer& rhs)
: Customer(rhs), // 呼叫基類拷貝構造函數
priority(rhs.priority) {}
PriorityCustomer& operator=(const PriorityCustomer& rhs) {
Customer::operator=(rhs); // 呼叫基類拷貝賦值運算符
priority = rhs.priority;
return *this;
}
};
將共同邏輯提煉至私有輔助函數(常命名為 init 或 copyFrom),由兩個 copying 函數共同調用:
class Widget {
// ...
private:
void copyFrom(const Widget& rhs) {
// 複製所有成員、基類部分
}
public:
Widget(const Widget& rhs) { copyFrom(rhs); }
Widget& operator=(const Widget& rhs) {
if (this != &rhs) copyFrom(rhs);
return *this;
}
};
Copying 函數必須確保複製「對象內所有成員變量」及所有「基類部分」。
切勿嘗試以某個 copying 函數實現另一個。應將共同功能放入第三個函數,由兩者共同調用。