虛函數表,以及虛函數指針


1)每個有虛函數的類都有自己的虛函數表,每個包含虛函數的類對象都有虛函數表指針。

2)對於多重繼承,如果多個基類都有虛函數,則繼承類中包含多個基類虛函數表,子類的虛函數地址放在聲明的第一個基類虛函數表后面。

3)計算類對象的內存大小的時候,需要計算有多少個虛函數指針。

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

假設有如下所示的一個繼承關系:

虛函數繼承 - simple1110 - gino

在這個繼承關系中,子類沒有重載任何父類的函數。那么,在派生類的實例中,其虛函數表如下所示:

對於實例:Derive d; 的虛函數表如下:

虛函數繼承 - simple1110 - gino

我們可以看到下面幾點:

1)虛函數按照其聲明順序放於表中。

2)父類的虛函數在子類的虛函數前面。

我相信聰明的你一定可以參考前面的那個程序,來編寫一段程序來驗證。

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

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

虛函數繼承 - simple1110 - gino

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

虛函數繼承 - simple1110 - gino

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

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

2)沒有被覆蓋的函數依舊。

這樣,我們就可以看到對於下面這樣的程序,

Base *b = new Derive();

b->f();

由b所指的內存中的虛函數表的f()的位置已經被Derive::f()函數地址所取代,於是在實際調用發生時,是Derive::f()被調用了。這就實現了多態。

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

下面,再讓我們來看看多重繼承中的情況,假設有下面這樣一個類的繼承關系。注意:子類並沒有覆蓋父類的函數。

虛函數繼承 - simple1110 - gino

對於子類實例中的虛函數表,是下面這個樣子:

虛函數繼承 - simple1110 - gino

我們可以看到:

1) 每個父類都有自己的虛表。

2) 子類的成員函數被放到了第一個父類的表中。(所謂的第一個父類是按照聲明順序來判斷的)

這樣做就是為了解決不同的父類類型的指針指向同一個子類實例,而能夠調用到實際的函數。

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

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

下圖中,我們在子類中覆蓋了父類的f()函數。

虛函數繼承 - simple1110 - gino

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

虛函數繼承 - simple1110 - gino

我們可以看見,三個父類虛函數表中的f()的位置被替換成了子類的函數指針。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM