在 C++ 學習進階之路中,繼承與多態是區別於 C 語言的兩大核心特性,也是掌握 C++ 面向對象精髓的關鍵。本文將從定義、語法、內存模型、訪問控制、同名隱藏、類型兼容性、菱形繼承與虛繼承等維度,系統梳理繼承機制的完整知識體系。
繼承允許程序員在保持原有類特性基礎上進行擴展,產生新類(派生類)。已存在的類稱為基類或父類,新建的類稱為派生類或子類。這種機制呈現了面向對象的層次結構,體現「由簡單到複雜」的認知過程。

class Derived : 訪問限定符 Base {
// 派生類成員
};



核心規則:派生類內部始終可訪問基類的 public 與 protected 成員;private 成員存在但不可見。繼承方式只影響「基類成員在派生類中的呈現屬性」以及「外部代碼通過派生類對象訪問基類成員的權限」。
創建派生類對象時,內存佈局包含「基類部分」與「派生類自有部分」,因此需先調用基類構造函數,再調用派生類構造函數;析構順序相反。
class Base {
public:
Base() { cout << "B()"; }
~Base() { cout << "~B()"; }
};
class Derived : public Base {
public:
Derived() { cout << "D()"; }
~Derived() { cout << "~D()"; }
};
int main() {
Derived d; // 輸出: B() D() ~D() ~B()
}

當派生類與基類存在同名成員函數或變量(無論參數列表是否相同),派生類成員將隱藏基類同名成員。派生類對象無法直接調用基類被隱藏成員,需通過作用域解析符顯式指定:d.Base::Show()。
class Base { public: void Show() { ... } void Show(int a) { ... } };
class Derived : public Base { public: void Show() { ... } }; // 隱藏基類所有 Show
int main() {
Derived d;
d.Show(); // 調用 Derived::Show()
d.Show(1); // 編譯錯誤:基類 Show(int) 被隱藏
d.Base::Show(); // 正確:顯式調用基類版本
d.Base::Show(1); // 正確
}
公有繼承建立「is-a」關係,支持向上轉型:
Base* b = new Derived(); // 正確:向上轉型
b->ShowBase(); // 調用基類版本(靜態綁定)
Derived* d = (Derived*)b; // 強制向下轉型:編譯通過但極度危險
// 若 b 實際不指向 Derived,後續訪問導致未定義行為
總結:
private 成員在派生類不可訪問,需派生類訪問請用 protectedpublic 繼承 = 接口繼承,滿足 is-a 原則(絕大多數場景)protected/private 繼承 = 實現繼承,has-a 關係,極少使用class 默認 private 繼承,struct 默認 public 繼承,建議顯式聲明static 成員在整個繼承體系中僅有一個實例當兩個派生類繼承同一基類,再由某類同時繼承這兩個派生類,形成菱形結構。若無虛繼承,最底層派生類將包含兩份基類子對象,導致數據冗余與二義性調用。
class A {}; // 共同基類
class B : public A {};
class C : public A {};
class D : public B, public C {}; // D 含有兩個 A 子對象

在中間層繼承時加上 virtual 關鍵字,將共同基類聲明為虛基類。此時無論通過多少條路徑繼承,最底層派生類僅包含一份虛基類子對象,消除二義性與冗余。
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {}; // D 僅有一個 A 子對象
虛繼承引入虛基類指針(vbptr)或偏移量表,增加對象體積與訪問開銷。
class Base { public: int _pub; };
class Derived_one : virtual public Base { public: int _por; };
class Derived_two : virtual public Base { public: int _pri; };
class Derived : public Derived_one, public Derived_two { public: int _num; };
// 非虛繼承 sizeof(Derived) = 20 (兩份 Base::_pub)
// 虛繼承 sizeof(Derived) = 24 (一份 Base::_pub + vbptr 開銷)

繼承是 C++ 代碼復用與多態實現的基石。深入理解訪問控制語義、構造析構順序、同名隱藏規則、向上轉型安全性、虛繼承機制與代價,對於編寫健壯、可維護的 C++ 代碼至關重要。工程實踐中應堅守「公有繼承表達 is-a、優先組合而非繼承、謹慎使用虛繼承」的設計原則。