條款12 複製物件勿忘其每一個成分
總結:
1. 拷貝函式應該保證拷貝一個物件的所有資料成員以及所有的基類部分。
2. 不要試圖依據一個拷貝函式實現另一個。作為代替,將通用功能放入第三個供雙方呼叫的函式。
設計良好的物件導向系統中,封裝了物件內部,僅留兩個函式用於物件的拷貝:拷貝建構函式和拷貝賦值運算子,統稱為拷貝函式。編譯器生成版的copy函式會拷貝被拷貝物件的所以成員變數。
考慮一個表現顧客的類,這裡的拷貝函式是手工寫成的,以便將對它們的呼叫志記下來:
void logCall(const std::string&funcName); // 製造一個log entry
class Customer {
public:
...
Customer(const Customer& rhs);
Customer& operator=(const Customer& rhs);
...
private:
std::string name;
};
Customer::Customer(const Customer& rhs)
: name(rhs.name) // 複製rhs的資料
{logCall("Customer copy constructor");}
Customer& Customer::operator=(constCustomer& rhs)
{
logCall("Customer copy assignment operator");
name= rhs.name; //複製rhs的資料
return*this;
}
這裡的每一件事看起來都不錯,實際上也確實不錯——直到 Customer 中加入了另外的資料成員:
class Date { ... }; // 日期
class Customer {
public:
... // 同前
private:
std::string name;
Date lastTransaction;
};
在這裡,已有的拷貝函式只進行了部分拷貝:它們拷貝了 Customer 的 name,但沒有拷貝它的 lastTransaction。然而,大部分編譯器即使是在最高的警告級別也不出任何警告。結論顯而易見:如果你為一個類增加了一個資料成員,你務必要做到更新拷貝函式,你還需要更新類中的全部的建構函式以及任何非標準形式的 operator=。
一旦發生繼承,可能會造成此主題最暗中肆虐的一個暗藏危機。考慮:
PriorityCustomer::PriorityCustomer(constPriorityCustomer& rhs)
: Customer(rhs), // 呼叫基類的copy建構函式
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;
}
無論何時,你打算自己為一個派生類寫拷貝函式時,必須注意同時拷貝基類部分。那些成分往往是private,所以你不能直接訪問它們,應該讓派生類的拷貝函式呼叫相應的基類函式。當你寫一個拷貝函式,需要保證(1)拷貝所有本地資料成員以及(2)呼叫所有基類中的適當的拷貝函式。
· 拷貝函式應該保證拷貝一個物件的所有資料成員以及所有的基類部分。
在實際中,兩個拷貝函式經常有相似的函式體,而這一點可能吸引你試圖通過用一個函式呼叫另一個來避免程式碼重複。你希望避免程式碼重複的想法值得肯定,但是用一個拷貝函式呼叫另一個來做到這一點是錯誤的。
“用拷貝賦值運算子呼叫拷貝建構函式”和“用拷貝建構函式呼叫拷貝賦值運算子”都是沒有意義的。如果發現你的拷貝建構函式和拷貝賦值運算子有相似的程式碼,通過建立第三個供兩者呼叫的成員函式來消除重複。這樣的函式當然是 private 的,而且經常叫做 init。這一策略可以消除拷貝建構函式和拷貝賦值運算子中的程式碼重複,安全且被證實過。
· 不要試圖依據一個拷貝函式實現另一個。作為代替,將通用功能放入第三個供雙方呼叫的函式。
相關文章
- 第十篇:複製物件時切記複製每一個成分物件
- es6完全深複製一個物件物件
- 對於複製普通物件 深複製和淺複製是否一樣物件
- 複製物件物件
- JS物件複製:深複製和淺複製JS物件
- vue複製物件Vue物件
- js物件深複製JS物件
- JavaScript物件複製理解JavaScript物件
- iOS之物件複製iOS物件
- js深度複製物件JS物件
- 簡單問題:JAVA物件的淺複製,有一個疑問!Java物件
- js物件的複製方法JS物件
- SpringBoot物件複製Spring Boot物件
- JS物件深度克隆/複製JS物件
- C#中的物件深複製和淺複製C#物件
- javascript函式引數引用型別傳遞其實也是一個複製過程JavaScript函式型別
- 淺談JS中物件的淺複製和深複製JS物件
- Java中物件的深複製和淺複製詳解Java物件
- Java淺複製大揭秘:如何輕鬆複製兩個不同物件的某些相同屬性Java物件
- javascript如何複製一個陣列JavaScript陣列
- 條款13 以物件管理資源物件
- vue實現物件的複製Vue物件
- vue物件的深層複製Vue物件
- JS 複製陣列和物件JS陣列物件
- 複製物件重新賦值不改變原物件物件賦值
- More effective C++ 條款12 (轉)C++
- MySQL 8 複製(一)——非同步複製MySql非同步
- 將一個陣列複製到另一個陣列上陣列
- Laravel 一條 SQL 如何 count 多個欄位,Laravel 一條 sql 查詢每個分類的數量LaravelSQL
- 改變複製物件結構對高階複製的影響物件
- VUE js中複製物件 JSONVue物件JSON
- C# 高效能物件複製C#物件
- JS 物件如何實現深複製JS物件
- 談談Python中物件複製Python物件
- visio 物件複製到其他程式物件
- Java物件複製之MapStruct使用Java物件Struct
- [分享]javascript 陣列以及物件的深拷貝(複製陣列或複製物件)的方法JavaScript陣列物件
- 請給Array本地物件增加一個原型方法,它用於刪除陣列條目中重複的條目(可能有多個),返回值是一個包含被刪除的重複條目的新陣列。...物件原型陣列