虛函式表與多型記憶體布局

2022-08-21 10:54:10 字數 2152 閱讀 9453

參考部落格:

c++中 的虛函式的作用主要是實現了多型的機制。關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術 可以讓父類的指標有「多種形態」,這是一種泛型技術。

虛函式表

每個含有虛函式的類都有乙個虛函式表(virtual table)來實現的。簡稱為v-table。 c++的編譯器應該是保證虛函式表的指標存在於物件例項中最前面的位置(這是為了保證取到虛函式表的有最高的效能——如果有多層繼承或是多重繼承的情況下)。 這意味著我們通過物件例項的位址得到這張虛函式表,然後就可以遍歷其中函式指標,並呼叫相應的函式。

1、  每乙個類都有虛函式列表。

2、  虛表可以繼承,如果子類沒有重寫虛函式,那麼子類虛表中仍然會有該函式的位址,只不過這個位址指向的是基類的虛函式實現。如果基類3個虛函式,那麼基類的虛表中就有三項(虛函式位址),派生類也會有虛表,至少有三項,如果重寫了相應的虛函式,那麼虛表中的位址就會改變,指向自身的虛函式實現。如果派生類有自己的虛函式,那麼虛表中就會新增該項。

3、  派生類的虛表中虛函式位址的排列順序和基類的虛表中虛函式位址排列順序相同,子類獨有的虛函式放在後面。

當定義乙個有虛函式類的物件時,物件的第一塊的記憶體空間就是乙個指向虛函式列表的指標。

在這舉個例子

class base

virtual void g()

virtual void h()

};然後定義變數 base b;

看這幅圖:

注意:虛函式表在最後會有乙個結束標誌,為1說明還有虛表,為0表示沒有虛表了 。(編譯器不同,結束標誌可能存在差異)。

沒有任何的繼承,虛函式表如下圖

(二)一般繼承(有虛函式覆蓋)

如果子類中有虛函式過載了父類的虛函式,會是乙個什麼樣子?假設,我們有下面這樣的乙個繼承關係。如圖所示:

在這個類的設計中,只覆蓋了父類的乙個函式:f()。那麼,對於派生類的例項,其虛函式表會是下面的乙個樣子:

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

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

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

這樣就會出現

base *b = new derive();

b->f();

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

下面我們再看看多重繼承的情況:

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

從圖上我們可以看到

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

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

這樣做就是為了解決不同的父類型別的指標指向同乙個子類例項,而能夠呼叫到實際的函式。

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

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

子類虛函式列表如圖所示:

三個父類虛函式表中的f()的位置被替換成了子類的函式指標。這樣,我們就可以任一靜態型別的父類來指向子類,並呼叫子類的f()了。

c 虛函式表與多型

本篇文章是對b站上乙個課程的筆記 對於乙個空類,其sizeof值是1 對空類加入兩個普通成員函式,其sizeof仍然是1 只有成員變數會占用記憶體空間,普通成員函式並不會占用空間 繼續加入乙個虛函式,sizeof值變成了4!這是因為,如果類中存在虛函式,則編譯器就會在類中插入乙個看不見的成員變數,也...

類成員函式,虛函式及虛函式表,記憶體布局

類的普通成員函式 非static,非virtual,非friend class a 注意,當foo函式是虛函式,或者foo函式體內要用到類的成員變數時,上述呼叫全部錯誤,因為要根據物件位址偏移來尋找虛函式表或者成員變數 貌似類的成員函式,只有static函式可以用a fun 域操作符來訪問,普通函式...

虛函式表的指標的記憶體布局

dd ecx 03b35ea8 6cc5849c dchkdata.6cc5849c 03b35eac 003a0043 03b35eb0 0050005c 03b35eb4 006f0072 這兒先來看看虛函式表的指標的記憶體布局,具體看下例 include class class virtual...