矛盾:派生類需初始化繼承來的基類成員,但基類 private 成員在派生類不可訪問。
解決:派生類構造函數調用基類構造函數完成基類部分初始化。
class People {
protected: char* m_name; int m_age;
public: People(char* name, int age) : m_name(name), m_age(age) {}
};
class Student : public People {
float m_score;
public:
Student(char* name, int age, float score)
: People(name, age), m_score(score) { } // 調用基類構造 + 成員初始化
void display();
};
People(name, age) 在初始化列表中調用(函數頭部)A → B → C 順序構造| 情況 | 行為 |
|---|---|
初始化列表顯式調用 Base(args) | 調用指定構造函數 |
| 未顯式調用 | 自動調用 Base() (預設構造) |
| 無預設構造且未顯式調用 | 編譯錯誤 |
class People {
public:
People() : m_name("xxx"), m_age(0) { cout << "People()" << endl; }
People(char* name, int age) : m_name(name), m_age(age) { cout << "People(name,age)" << endl; }
protected: char* m_name; int m_age;
};
class Student : public People {
public:
Student() : m_score(0) { cout << "Student()" << endl; } // 隱式調用 People()
Student(char* name, int age, float score) : People(name, age), m_score(score) {
cout << "Student(name,age,score)" << endl;
}
void display();
private: float m_score;
};
int main() {
Student stu1; // 輸出: People() → Student()
Student stu2("小明",16,90.5); // 輸出: People(name,age) → Student(name,age,score)
}
class A { ... };
class B : public A { ... };
class C : public B {
C() : A(10) { } // 錯誤!C 只能調用直接基類 B 的構造
};
理由:B 構造時已調用 A,若 C 再調用將導致 A 雙重初始化。
Student(char* name, int age, float score)
: People("固定名", 18), m_score(score) { } // 常量實參
Student(char* name, int age, float score)
: People(local_var, compute_age()), m_score(score) { } // 區域變量/函數調用
| 錯誤寫法 | 問題 | 正確寫法 |
|---|---|---|
Student(...) { People(name, age); } | 函數體中調用,視為建立臨時物件,非初始化基類 | 初始化列表 : People(name, age) |
| 忘記調用基類帶參構造 | 隱式調用預設構造,可能非預期行為/編譯錯誤 | 顯式列出 : Base(args) |
| 嘗試調用間接基類 | 編譯錯誤 | 只調用直接基類 |
{})Student() : Student("default", 0, 0) {}using Base::Base; 直接繼承基類構造簽名派生類構造函數通過初始化列表調用直接基類構造完成基類部分初始化。核心鐵律:基類優先構造、按聲明順序、只能調用直接基類、未顯式則用預設構造。掌握這些機制,配合現代 C++ 委託/繼承構造特性,能編寫高效、正確、可維護的物件初始化代碼。