c++ 虛函數 虛函數表 個人理解

參考文章:https://blog.csdn.net/qq_20309055/article/details/79298593

整理一份關於虛函數和繼承關係的腦圖

前言

C++中的虛函數的作用主要是實現了多態的機制。關於多態,簡而言之就是用父類型別的指針指向其子類的實例,然後通過父類的指針調用實際子類的成員函數。這種技術可以讓父類的指針有“多種形態”,這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的代碼來實現可變的算法。比如:模板技術,RTTI技術,虛函數技術,要麼是試圖做到在編譯時決議,要麼試圖做到運行時決議。

動態綁定的實現

在說動態綁定之前,我們需要先了解一下什麼叫靜態綁定,之前學習單片機的彙編語言的時候,我們知道調用一個子程序,或者是中斷處理函數等需要打斷當前運行進行跳轉的行爲叫做CALL(調用),大部分的彙編都是這麼寫的CALL 後面接的是address,指明瞭需要執行函數的入口地址。這就叫做靜態綁定,在編譯之後生成的彙編代碼裏面直接指定在什麼位置我們需要調用什麼樣的函數。運行的時候都是去固定的位置去執行。

而動態綁定表示,當我們通過類的指針去執行內部的函數的時候,編譯器就會知道不能簡單的執行靜態綁定。 要通過vptr找到vtbl去查找應該執行哪個函數,在表裏面找到相應的函數位置去執行,而不是在編譯的時候就直接指定好了地址。

如何實現查找一個虛函數在虛函數表的位置?

編譯器會按照編譯時找到的虛函數的位置而安排在table的相應位置,調用虛函數的時候,編譯器就會知道自己之前放的虛函數是放在虛函數的哪一個位置。大致邏輯就是這樣,關於動態綁定部分以及虛函數表的搜索部分下次再去查一下,總結一下。

一般繼承(有虛函數覆蓋)

覆蓋父類的虛函數是很顯然的事情,不然,虛函數就變得毫無意義。下面,我們來看一下,如果子類中有虛函數重載了父類的虛函數,會是一個什麼樣子?假設,我們有下面這樣的一個繼承關係。

                                                                                  

爲了讓大家看到被繼承過後的效果,在這個類的設計中,我只覆蓋了父類的一個函數:f()。那麼,對於派生類的實例,其虛函數表會是下面的一個樣子:

                                       

我們從表中可以看到下面幾點

1)覆蓋的f()函數被放到了虛表中原來父類虛函數的位置

2)沒有被覆蓋的函數依舊存在子類的虛表之中

3)父類的虛函數放在子類的前面

多重繼承(有虛函數覆蓋)

下面我們再來看看,如果發生虛函數覆蓋的情況。

下面是對於子類實例中的虛函數表的圖:

我們可以看見,三個父類虛函數表中的f()的位置被替換成了子類的函數指針。這樣,我們就可以任一靜態類型的父類來指向子類,並調用子類的f()了。體現一個問題就是如果出現多繼承的情況那麼將會創建父類個數的虛表。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章