C++ 類別中有四個編譯器會自動生成的特殊成員函數:**建構函數、解構函數、複製建構函數、複製指派運算子**。理解它們的觸發時機、預設行為與自訂必要性,是寫出正確、高效 C++ 程式碼的關鍵。本文整理自《C++ 沉思錄》核心觀點,輔以實戰經驗。
const/reference 成員、執行基類/成員子物件建構 → **必須自訂建構函數**。public:介面契約,穩定、最小、完整。private:實作細節、不變式保護、資源所有權。protected:僅供衍生類別存取,**慎用**;傾向 private + protected 虛函數 (Template Method)。private 資料成員,可提供 const T& 唯讀存取,避免複製開銷,且保證封裝性。class Stick {
const int &length; // 唯讀參考,綁定至 true_length
int true_length;
public:
Stick(int l = 1) : true_length(l), length(true_length) {}
void setLength(int v) { true_length = v; } // length 自動同步
};Stick arr[1024]; 需無參建構函數逐一初始化元素。vector<Stick> v(10); 同理。= delete) 以防誤用。const/reference 成員、無預設建構函數的成員)。malloc),可延遲初始化,但需建立「已初始化」旗標防止誤用。std::unique_ptr, std::fstream 已遵循 RAII)。new,解構函數必須 delete。只有當類別作為「多態基類」被 delete 時 才需要虛擬解構函數。
class Base { public: virtual ~Base() {} }; // 正確
class Derived : public Base { ~Derived() { cout << "~Derived\n"; } };
Base *p = new Derived;
delete p; // 呼叫 Derived::~Derived() → Base::~Base()
delete p 僅呼叫 Base::~Base(),**衍生類別解構函數不被調用** → 資源洩漏、行為未定義。編譯器合成的複製建構函數執行**成員逐位複製 (shallow copy)**。需自訂當:
private 複製建構函數且不實作 (C++11: = delete)。class String {
char *data;
String(const String&); // 私有,禁止複製
String& operator=(const String&); // 私有,禁止指派
public:
// ...
};
T a = b; (複製初始化) 呼叫**複製建構函數**,非指派運算子。if (this == &rhs) return *this; 防止 a = a 導致資源提前釋放。Copy-and-swap 慣用語。String& operator=(String rhs) { // 以值傳遞利用複製建構函數
swap(*this, rhs);
return *this;
}*this 參考**,支援鏈式指派 a = b = c。| 函數 | 預設行為 | 需自訂條件 | C++11 現代寫法 |
|---|---|---|---|
| 建構函數 | 無參、成員預設建構 | 資源獲取、不變式建立、const/ref 成員 | 委派建構、預設/刪除 |
| 解構函數 | 成員逆序解構 | 釋放非 RAII 資源 | 虛擬/預設/刪除 |
| 複製建構 | 淺複製 | 深複製、禁止複製 | = default / = delete |
| 複製指派 | 淺指派 | 深複製、禁止指派、自指派安全 | Copy-and-swap / = default / = delete |
掌握這四大函數的生命週期、觸發條件與自訂策略,是從「會寫 C++」邁向「寫好 C++」的分水嶺。