【C++ 筆記】繼承(Inheritance) - part 22
【C++ 筆記】繼承(Inheritance) - part 22
很感謝你點進來這篇文章。
你好,我並不是什麼 C++、程式語言的專家,所以本文若有些錯誤麻煩請各位鞭大力一點,我極需各位的指正及指導!!本系列文章的性質主要以詼諧的口吻,一派輕鬆的態度自學程式語言,如果你喜歡,麻煩留言說聲文章讚讚吧!
OOP 四大特性
首先讓我們複習一下 OOP(物件導向程式設計) 四大特性:
- 封裝(Encapsulation)
- 繼承(Inheritance)
- 多型(Polymorphism)
- 抽象(Abstraction)
封裝在前面我們已經有學過了,其實就是使用存取修飾子 private 或 protected 來限制資料成員的權限,不被其他程式碼控制。
封裝就跟他的名字一樣,一個被封裝的紙箱,箱子外的人看不見裡面的東西是啥,只有透過打開這個行為(方法)才能進一步看到箱子裡的東西,而這個行為就是限制了外人存取資料成員的權限。
:::success
封裝具體定義:將資料和運算這些資料的方法組合在一個類別(Class)中,並透過存取控制來限制對資料的直接存取。
:::
封裝主要有以下四種用途跟目的:
- 資料隱藏:防止外部「直接」存取物件的內部資料,保護資料的完整性和一致性。
- 介面與實現分離:外部只需透過公開的介面(方法)與物件互動,不必看到內部實現細節。
- 模組化(modularity):將功能封裝在類別中,使程式結構更清晰,易於維護和擴展。
- 提高安全性:透過控制存取權限,防止未授權的資料修改。
總之,封裝他主要做的事情就是「隱藏」,將資料隱藏,做安全性措施。實際上可以透過 const、static member、friend 去做控制。
繼承(Inheritance)
本篇要說明的 OOP 四大特性之二,就是繼承(Inheritance)。
:::info
定義:繼承是一種機制,允許一個類別(衍生類)基於另一個類別(基類)來定義,並繼承其非私有的成員(包括資料和方法)。
:::
衍生類(derived-class):從基類衍生出來的。
衍生類我們也可以稱之為「子類別」,而基類也可稱為「父類別」。
簡單來說,繼承的概念可從下例去做理解:
假設動物(Animal)是基類(最根本的類別),而動物可以往下分類,比如說人類也是一種動物,狗、貓都也是動物。
所以可以再細分如下:
Animal() -> Human()、Dog()、Cat()
Human()、Dog()、Cat() 本身都「繼承」了 Animal() 的特性。(因為都是動物嘛,既然都是動物,他們一定都會有共同的特徵。)
語法(Syntax)
1 | class derived_class_name : access-specifier base_class_name |
derived_class_name:衍生類名稱。
access-specifier:存取修飾子。
base_class_name:基類名稱。
Note: A derived class doesn’t inherit access to private data members. However, it does inherit a full parent object, which contains any private members which that class declares.
by:https://www.geeksforgeeks.org/inheritance-in-c/
注意:衍生類別不會繼承對私有資料成員的存取權限。但它確實繼承了一個完整的父物件,其中包含該類別宣告的任何私有成員。
範例 1:繼承的使用方法
以下是個範例:
1 |
|
來源:https://www.runoob.com/cplusplus/cpp-inheritance.html
輸出結果:
1 | Total area: 35 |
以上範例中,基類被定義成 Shape,並設定資料成員 width、height,及兩個 methods:setWidth、setHeight。
而衍生類被定義為 Rectangle,繼承 Shape 的資料成員跟方法。
所以可以在主函數中看到,衍生類能夠使用 Shape 的方法去設定長寬。
繼承的存取控制
以下列表,表示各個型態的類別是否能夠從 public、protected、private 中進行存取。
| 存取類型 | public | protected | private |
|---|---|---|---|
| 同一個類別裡面 | yes | yes | yes |
| 衍生類別 | yes | yes | no |
| 類別的外面(外部類別) | yes | no | no |
表格來源:https://www.runoob.com/cplusplus/cpp-inheritance.html
一個衍生類別繼承了所有的基類別方法,但下列情況除外:
- 基類別的建構子、解構子和複製建構子。
- 基類別的重載運算子。
- 基類別的 Friend Function。
範例 2:建構子、解構子在繼承的行為
衍生類的建構子會先自動呼叫基類的建構子,然後執行自己的建構子。
以下範例程式碼的輸出結果,就可看出這東西的先後順序。
1 |
|
輸出結果:
1 | Base constructor |
繼承類型(存取修飾子)
我們可以特別指定要繼承 public 還是 private,又或是 protected。
通常在程式設計上普遍會使用 public。
:::info
如果繼承時沒特別指定存取修飾子,預設使用 private。
:::
以下資訊來自:https://www.runoob.com/cplusplus/cpp-inheritance.html
當使用不同類型的繼承時,遵循以下幾個規則:
- 公有繼承(public):當一個類別衍生自「公有」基類別時,基類的「公有」成員也是衍生類別的「公有」成員,基類的「保護」成員(protected)也是衍生類的「保護」成員(protected),基類的「私有」成員(private)不能直接被衍生類存取,但是可以透過呼叫基類的「公有」和「保護」成員來存取。
- 保護繼承(protected): 當一個類別衍生自保護基類別時,基底類別的公有和保護成員將成為衍生類別的保護成員。
- 私有繼承(private):當一個類別衍生自私有基底類別時,基底類別的公有和保護成員將成為衍生類別的私有成員。
其實以上這些資訊可從下圖直接明瞭看出:

Image Source:https://www.geeksforgeeks.org/inheritance-in-c/
左欄藍色的為基類成員的存取修飾子,而黑色的為繼承模式。
這個表就是在說當繼承基類的時候,不同存取修飾子會有怎樣的行為。
當衍生類指定為 public 時,基類的 public、protected 都不會受繼承影響而改變,反倒是最後一個基類的 private 會被隱藏起來,不能直接存取。
而後衍生類的 protected,會將基類的 public 變成 protected;private 將首兩項全變成 private。
:::success
我自己是用權限大小來理解,依照這個表格來看就是(權限由小到大):public -> protected -> private。
public 因為權限最小,所以繼承時基類的 public 還是 public,基類的 protected 還是 protected。因為 private 權限最大嘛,所以不管你是外部還是繼承都不能偷看他的資料。
接下來就以此類推。
:::
範例 3:繼承模式
1 |
|
輸出結果:
1 | Public Inheritance: |
多重繼承(Multiple inheritance)
語法:
1 | class A |
就是一個衍生類繼承自多個類別,如 class C,同時繼承了 A、B 類別。
範例 4:多重繼承
from:GeeksForGeeks
1 |
|
輸出結果:
1 | B's constructor called |
菱形問題(Diamond Problem)
範例 4 的多重繼承,很有可能會造成所謂的菱形問題。
以下是引用自 GeeksForGeeks 的一段話跟圖片:
The diamond problem occurs when two superclasses of a class have a common base class. For example, in the following diagram, the TA class gets two copies of all attributes of Person class, this causes ambiguities.
當一個類別的兩個超類別(層次較高的類別)有一個共同的基類時,就會出現菱形問題。例如,在下圖中,TA 類別獲得了 Person 類別的所有屬性的兩個副本,這會導致歧義。

翻譯一下:
:::info
Student、Faculty 都是 Person 的衍生類,而 TA 多重繼承自 Student、Faculty 兩個類別,但是這樣做會在 C++ 裡面發生一個問題叫菱形問題,也就是 TA 會擁有兩套 Person 實例資料的問題。因此實例化 TA 的時候,Person 的建構子會被呼叫兩次,然後解構子也會。
:::
為了要解決這個問題,所以可以透過一個關鍵字叫做 virtual 加在 Student、Faculty 類旁邊(因為被 TA 多重繼承),像是:
1 | class Faculty : virtual public Person { |
加了關鍵字 virtual 的繼承也稱為虛繼承(or 虛擬繼承)。
範例 5:虛繼承
1 |
|
輸出結果:
1 | Class A display |
範例 6:帶有資料成員的虛繼承
1 |
|
輸出結果:
1 | A constructor, value = 42 |
多級繼承(Multilevel Inheritance)
多級繼承很容易和多重繼承搞混,所以作者設計下表讓觀念稍微清晰一些:
| 特性 | 多級繼承(Multilevel Inheritance) | 多重繼承(Multiple Inheritance) |
|---|---|---|
| 基類數量 | 每個類別只有一個直接繼承的基類 | 衍生類可有多個直接繼承的基類 |
| 結構 | 垂直層次結構(如 A -> B -> C) | 平行結構(如 D 繼承 B 和 C) |
| 關係 | 像是「單一血統」的繼承關係 | 像是「多重來源」的繼承關係 |
| 複雜性 | 較易,無歧義問題 | 較複雜,有菱形問題 |
| 應用 | 動物 -> 哺乳動物 -> 狗 | 學生同時繼承「人」和「學員身分」特性 |
| 是否虛繼承 | 否 | 是 |
GeeksForGeeks 給多級繼承舉了一個例子,如下:
1 | Base class-> Wood, Intermediate class-> furniture, subclass-> table |
基類 -> Wood(木頭), 間接類 -> furniture(家具), 子類 -> table(桌子)

Image Source:https://www.geeksforgeeks.org/cpp-multilevel-inheritance/
語法如下:
1 | class A // base class |
範例 7:多級繼承
1 |
|
輸出結果:
1 | Father method |
總結
仍有其他的繼承模式,如:Hierarchical Inheritance(層次繼承)、Hybrid Inheritance(混合繼承),但這些都是基於前面的多重、多級繼承,而且概念類似,但礙於篇幅原因所以到此為止。
複習 OOP 四大特性:
- 封裝(Encapsulation)
- 繼承(Inheritance)
- 多型(Polymorphism)
- 抽象(Abstraction)
繼承定義:繼承是一種機制,允許一個類別(衍生類,Derived Class,或稱子類別)基於另一個類別(基類,Base Class,或稱父類別)定義,並繼承其非私有成員(包括資料和方法)。
如:Animal 是基類,Human、Dog、Cat 是衍生類,這些子類別繼承了 Animal 的共同特徵。
語法:
1 | class DerivedClassName : access-specifier BaseClassName { |
- access-specifier:存取修飾子(public、protected、private)。
- 注意:衍生類無法直接存取基類的 private 成員,但繼承了包含這些成員的完整物件。
存取權限表(來自菜鳥教程):
| 存取類型 | public | protected | private |
|---|---|---|---|
| 同一個類別裡面 | yes | yes | yes |
| 衍生類別 | yes | yes | no |
| 類別的外面(外部類別) | yes | no | no |
例外:基類的建構子、解構子、重載運算子和 friend 函數不會被繼承。
繼承模式表(from GeeksForGeeks):

多重繼承定義:一個衍生類同時繼承多個基類。
語法:
1 | class A |
多重繼承會遇到的菱形問題:當多個基類共享同一祖先類時,可能導致衍生類擁有該祖先的多份副本,造成歧義。
解決方案:虛繼承(virtual inheritance),使用 virtual 關鍵字讓祖先類只有一份實例。
多級繼承(把他想成是線性的就對了)定義:類別層次結構逐級繼承(如 A -> B -> C)。
多重繼承與多級繼承比較表:
| 特性 | 多級繼承(Multilevel Inheritance) | 多重繼承(Multiple Inheritance) |
|---|---|---|
| 基類數量 | 每個類別只有一個直接繼承的基類 | 衍生類可有多個直接繼承的基類 |
| 結構 | 垂直層次結構(如 A -> B -> C) | 平行結構(如 D 繼承 B 和 C) |
| 關係 | 像是「單一血統」的繼承關係 | 像是「多重來源」的繼承關係 |
| 複雜性 | 較易,無歧義問題 | 較複雜,有菱形問題 |
| 應用 | 動物 -> 哺乳動物 -> 狗 | 學生同時繼承「人」和「學員身分」特性 |
| 是否虛繼承 | 否 | 是 |
參考資料
C++ Multilevel Inheritance | GeeksforGeeks
Virtual inheritance - Wikipedia
superclass 並不超級 - Huan-Lin 學習筆記
Multiple Inheritance in C++ | GeeksforGeeks


