多態詳細解讀
- 多態的概念
- 多態的構成條件
- 接口繼承和實現繼承:
- 多態的原理:
- 動態綁定和靜態綁定
- 多繼承中的虛函數表
多態的概念
-通俗的來說:當不同的對象去完成某同一行為時,會產生不同的狀態。
多態的構成條件
- 必須通過基類的指針或者引用調用
虛函數
1 - 虛函數的重寫2 – 三同(函數名,參數,返回值)
EG:
函數重寫的兩個例外:
- 協變(基類與派生類虛函數返回值類型不同):
但是僅僅支持返回各自的對象的指針或者引用。- 析構函數的重寫(基類與派生類析構函數的名字不同):
雖然析構函數的函數名不同,但是編譯器會做特殊的處理,統一處理成destructor(前提是基類的析構函數加了virtual)
接口繼承和實現繼承:
- 普通函數的繼承叫做實現繼承,雖然連函數名和參數等等也全部繼承,但是主要是繼承實現,且派生類可以直接使用。
- 虛函數的繼承是接口繼承,為了實現重寫(重寫實現操作)
到這里可能有些小伙伴會不太理解
接口
是什么,這里我們用一個例子來解釋:
問:*p->test( )此時打印出來的結果是什么呢?
是不是第一眼就覺得是B->0呢?我們來看看解析:
多態的原理:
- 首先我們先要理解
函數虛表
這個概念,函數虛表里面存放著虛函數的地址。(為了描述方便,下面都稱之為虛表) - 當滿足多態的兩個條件之后:如果傳給基類的指針的是子類對象的地址,那就會去調用子類的虛表里面重寫之后的對應函數,如果傳的是基類對象的地址,那么就會去基類自身的虛表里面找對應的函數。
圖例:
這時候有同學就要問了:這個基類的虛表和子類的虛表是同一張嗎?虛表到底有幾張?
-
只要有虛函數,那么對于各種類,他們都有各自的虛表。并且如果派生類(既然叫做派生類,說明是繼承了某個類作為基類)中有實現虛函數
fun1
的重寫,那么就會在自身的虛表中覆蓋掉從原來基類中的繼承下來的fun1
的實現(虛函數是接口繼承,原函數的實現被覆蓋),正因如此才能實現多態。 -
所以基類和子類的虛表不是同一張,每個類都有自己的虛表
動態綁定和靜態綁定
- 靜態綁定就是在程序編譯期間,就明確了程序的行為。比如函數的重載
- 動態綁定也叫做后期綁定,就是在程序運行期間,根據傳過來的類型去
*確定具體的行為*
,比如上述的不同的身份去購買車票會。 細節點
:虛表是在編譯的時候就生成了,但是對象中只存儲指向虛表的指針(由于虛表實際叫做函數指針數組,那么虛表的指針就叫做函數指針數組的指針,這個指針
是在對象執行構造函數
的時候生成的。)
多繼承中的虛函數表
這里主要清楚:對于多繼承的派生類,其本身未重寫的虛函數放在其第一個繼承的父類部分的虛表中。(但是這里要意識到大的來看此處仍然是在派生類的虛表,是派生類虛表中所繼承的父類的虛表部分。)
虛函數:被virtual修飾的成員函數就稱為虛函數 ??
虛函數的重寫:虛函數的重寫(覆蓋):派生類中有一個跟基類完全相同的虛函數(即派生類虛函數與基類虛函數的返回值類型、函數名字、參數列表完全相同),稱子類的虛函數重寫了基類的虛函數。 ??