class Animal {
int weight, height;
public:
// 方式 A:初始化列表(推薦)
Animal(int w, int h) : weight(w), height(h) {}
// 方式 B:構造函數體賦值
Animal(int w, int h) { weight = w; height = h; }
};
對內建類型(int、指針等)無性能差異,但方式 A 更統一、可用於所有場景。
class Animal {
public:
Animal(int w, int h) : weight(w), height(h) {} // 無 Animal()
private:
int weight, height;
};
class Dog : public Animal {
public:
// 必須在初始化列表調用基類構造
Dog(int w, int h, int t) : Animal(w, h), type(t) {}
private:
int type;
};
對象構造順序:基類 → 成員 → 派生類。基類構造必須在派生類構造體前完成。
class Dog {
const int LEGS = 4; // C++11 類內初始化
// 或
const int LEGS;
Dog() : LEGS(4) {} // 必須在初始化列表初始化
};
const 成員不可賦值,只能初始化。
class Dog {
int& ref; // 必須綁定初始化
Dog(int& r) : ref(r) {}
};
class Food {
public:
Food(int t=10) : type(t) { cout << "Food構造\n"; }
Food(const Food&) { cout << "Food拷貝構造\n"; }
Food& operator=(const Food&) { cout << "Food賦值\n"; return *this; }
private:
int type;
};
class Dog {
Food food;
public:
// 方式 A:初始化列表 → 直接拷貝構造
Dog(const Food& f) : food(f) { cout << "Dog構造A\n"; }
// 方式 B:構造函數體賦值 → 默認構造 + 賦值
Dog(const Food& f) { food = f; cout << "Dog構造B\n"; }
};
效率差異:方式 A 一次拷貝構造;方式 B 一次默認構造 + 一次賦值運算符。對複雜類型差距巨大。
成員初始化順序僅取決於類中聲明順序,與初始化列表書寫順序無關!
class Bad {
int a, b;
Bad(int x) : b(x), a(b) {} // 危險!a 用 b 初始化,但 a 先聲明 → a 先初始化 → 讀取未初始化的 b
};
最佳實踐:初始化列表順序與聲明順序一致,開啟編譯器警告(-Wreorder)。
struct Point { int x, y; };
Point p1{1, 2}; // 列表初始化
Point p2 = {1, 2}; // 同前
vector v = {1,2,3}; // 初始化列表構造
| 場景 | 必須用列表? | 建議 |
|---|---|---|
| 內建類型成員 | 否 | 統一風格用列表 |
| 基類無默認構造 | 是 | 必須 |
| const/引用成員 | 是 | 必須 |
| 類類型成員 | 否 | 強烈建議(避免默認構造+賦值) |
| 成員相互依賴 | 視情況 | 注意聲明順序 |