繼承是 C++ 面向對象的基石,實現**類型層次**與**代碼復用**。本文系統梳理繼承的語義分類、訪問控制、構造/析構順序、對象切片風險、虛函數表繼承、組合優於繼承原則,附完整代碼驗證關鍵行為。
| 類型 | 關鍵字 | 語義 | 典型用途 |
|---|---|---|---|
| 公有繼承 | public | **IS-A** (是一種) — 派生類**是**基類的一種,滿足里氏替換原則 | 接口繼承、多態基類 |
| 保護繼承 | protected | **Implemented-in-terms-of** — 派生類**根據**基類實現,對外隱藏基類接口 | 實現繼承、受控擴展 |
| 私有繼承 | private | **Implemented-in-terms-of** (更強封裝) — 基類接口完全內部化 | 策略類、CRTP 基類 |
基類成員 public繼承 protected繼承 private繼承 public → public protected private protected → protected protected private private → 不可訪問 不可訪問 不可訪問
class Base { public: Base() { cout << "Base()\n"; } ~Base() { cout << "~Base()\n"; } };
class Member { public: Member() { cout << "Member()\n"; } ~Member() { cout << "~Member()\n"; } };
class Derived : public Base { Member m; public: Derived() { cout << "Derived()\n"; } ~Derived() { cout << "~Derived()\n"; } };
int main() { Derived d; }
// 輸出:
// Base()
// Member()
// Derived()
// ~Derived()
// ~Member()
// ~Base()
void Process(Base b) { b.VirtualFunc(); } // 參數按值傳遞!
Derived d;
Process(d); // 發生切片:只複製 Base 部分,虛函數調用 Base 版本
| 場景 | 繼承缺點 | 組合方案 |
|---|---|---|
| 需要複用基類實現 | 暴露基類所有接口、耦合構造析構、切片風險 | 嵌入基類對象作成員,僅轉發所需接口 |
| 多態需求 | 繼承僅是實現多態之一途徑 | 介面類 (純虛類) + 組合實現類 + 委托 |
| 策略可變 | 繼承靜態綁定策略 | 策略模式:組合策略接口,運行時替換 |
繼承是強大但危險的工具。**理解其語義、內存模型、構造語義、切片陷阱**,並在架構層面優先選擇組合、介面隔離、策略模式,才能寫出健壯、可維護的 C++ 類體系。