c++是如何實現多繼承帶來的多態問題?

波波桑


多態是指同樣的消息被不同類型的對象接收時導致完全不同的的行為。有虛函數的類才能叫多態類型的類,可以從探索虛函數是如何實現動態綁定的來了解如何實現多繼承中的多態。

單繼承時虛函數動態綁定的實現原理

每個類各有一個虛表(虛函數表),虛表的內容是由編譯器安排的。c++語言並沒有規定虛函數表的內容。派生類的虛表中,基類聲明的虛函數對應的指針放在前面,派生類新增的虛函數的對應指針放在後面,這樣一個虛函數 的指針在基類虛表和派生類虛表中具有相同的位置。每個多態類型的對象中都有一個指 向當前類型的虛表的指針,該指針在構造函數中被賦值。當通過基類的指針或引用調用 一 個虛函數時,就可以通過虛表指針找到該對象的虛表,進而找到存放該虛函數的指針的虛表條目。將該條目中存放的指針讀出後,就可獲得應當被調用的函數的入口地址,然後 調用該虛函數,虛函數的動態綁定就是這樣完成的。

如下圖所示:

由上圖可以看到基類Base有f(),g()函數,派生類還有新增的h()函數,那麼這種單繼承的虛函數實現動態綁定的方式是這樣的:

從這張超大圖片可以看到,每個Base對象都有一個指向Base的虛表的指針,虛表存放著指向每個函數的指針,這些指針存放著對應函數的地址,這樣通過虛表指針就能找到虛表,通過虛表就能找到函數指針,通過函數指針就能找到函數,這樣虛函數的動態綁定就完成了。派生類Base2也一樣。

溫馨提示:執行一個類的構造函數時,首先被執行的是基類的構造函數,因此構造一個派生類的對象時,該對象的虛表指針首先會被指向基類的虛表。只有當基類構造函數執行完後,虛表指針才會被指向派生類的虛表,這就是基類構造函數調用虛函數時不會調用派生類的虛函數的原因。

在多繼承時,情況會變得更加複雜,因為在多繼承時,情況會更加複雜,因為每個基類都有各自的虛函數,這樣繼承了多個基類的派生類需要多個虛表(或一個虛表分為多段,每個基類的虛表指針指向其中一段的地址。因為有些編譯器把多個虛表連成一個)如圖所示:

派生類Base3公有繼承了Base,Base2,那麼虛函數動態綁定的實現方式是這樣的:

提示:多重繼承時,派生類新增的成員放在第一個表,比如上圖Base3()的虛表的m()指針。

事實上,一個類的虛表中存放的不只是虛函數的指針,用於支持運行時類型識別的對象的運行時類型信息也需要通過虛表來訪問,只有多態類型有虛表,因此只有多態類型支持運行時類型識別。

以上就是我的回答,有不同意見的歡迎來討論,喜歡我的回答請關注,我們一起學習。


分享到:


相關文章: