1. 程式人生 > >C++中單繼承與多重繼承下的虛擬函式表

C++中單繼承與多重繼承下的虛擬函式表

轉自:http://www.cnblogs.com/Z465360621/articles/4561344.html
虛擬函式表,以及虛擬函式指標:
1)每個有虛擬函式的類都有自己的虛擬函式表,每個包含虛擬函式的類物件都有虛擬函式表指標。
2)對於多重繼承,如果多個基類都有虛擬函式,則繼承類中包含多個基類虛擬函式表,子類的虛擬函式地址放在宣告的第一個基類虛擬函式表後面。
3)計算類物件的記憶體大小的時候,需要計算有多少個虛擬函式指標。

一般繼承(無虛擬函式覆蓋)
假設有如下所示的一個繼承關係:
這裡寫圖片描述
在這個繼承關係中,子類沒有過載任何父類的函式。那麼,在派生類的例項中,其虛擬函式表如下所示:

對於例項:Derive d; 的虛擬函式表如下:
這裡寫圖片描述


我們可以看到下面幾點:

1)虛擬函式按照其宣告順序放於表中。

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

一般繼承(有虛擬函式覆蓋)
覆蓋父類的虛擬函式是很顯然的事情,不然,虛擬函式就變得毫無意義。下面,我們來看一下,如果子類中有虛擬函式過載了父類的虛擬函式,會是一個什麼樣子?假設,我們有下面這樣的一個繼承關係。
這裡寫圖片描述
為了讓大家看到被繼承過後的效果,在這個類的設計中,我只覆蓋了父類的一個函式:f()。那麼,對於派生類的例項,其虛擬函式表會是下面的一個樣子:
這裡寫圖片描述
我們從表中可以看到下面幾點,

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

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

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

Base *b = new Derive();

b->f();

由b所指的記憶體中的虛擬函式表的f()的位置已經被Derive::f()函式地址所取代,於是在實際呼叫發生時,是Derive::f()被呼叫了。這就實現了多型。

多重繼承(無虛擬函式覆蓋)
下面,再讓我們來看看多重繼承中的情況,假設有下面這樣一個類的繼承關係。注意:子類並沒有覆蓋父類的函式。
這裡寫圖片描述
對於子類例項中的虛擬函式表,是下面這個樣子:
這裡寫圖片描述
我們可以看到:

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

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

這樣做就是為了解決不同的父類型別的指標指向同一個子類例項,而能夠呼叫到實際的函式。(強制轉換的時候使用dynamic_cast)

多重繼承(有虛擬函式覆蓋)
下面我們再來看看,如果發生虛擬函式覆蓋的情況。

下圖中,我們在子類中覆蓋了父類的f()函式。
這裡寫圖片描述
下面是對於子類例項中的虛擬函式表的圖:
這裡寫圖片描述
我們可以看見,三個父類虛擬函式表中的f()的位置被替換成了子類的函式指標。