虛函式在c++裡的作用是在是非常非常的大,很多講述c++的文章都會講到它,要用好c++,就一定要學好虛函式。本文對虛函式的一些實現機制,以及c++物件布局做一下探索。
虛函式的作用是實現動態聯編,也就是在程式的執行階段動態地選擇合適的成員函式,在定義了虛函式後,可以在基類的派生類中對虛函式重新定義,在派生類中重 新定義的函式應與虛函式具有相同的形參個數和形參型別。以實現統一的介面,不同定義過程。如果在派生類中沒有對虛函式重新定義,則它繼承其基類的虛函式。 那麼,這個動態聯編是怎麼實現的呢?
下面看乙個簡單例子:
class aa
virtual void fun1()
};class bb :public aa
void ff(){};
};class cc :public aa
void fun()
};首先要明確的是,在有虛函式的類中,有乙個隱藏的成員指標變數vfptr,虛函式的神秘之處就在於這個東西。這是乙個指標,它是指向虛函式表的指標,好啦,又出現了乙個新詞,虛函式表,它就是存放虛函式位址的一張表,(不用關心它的資料結構是咋樣的)。可以通過這個虛函式表找到虛函式的入口位址。ok,名詞解釋完畢.(我有點廢).
總 的說來就是,在有虛函式的類中,一定會有乙個虛函式表指標vfptr,這個vfptr指標會放在類的起始處,虛函式表裡會按基類宣告虛函式的順序在 vfptr裡存放虛函式的位址,虛函式表裡存放的是虛函式的位址,是具體子類的實現函式的位址。呼叫虛函式的時候,是從vfptr所指的函式表裡獲取到函 數字址,然後才呼叫具體的**。
當把乙個繼承類的指標賦值給基類指標時,基類的指標就指向了繼承類的記憶體,此時的vfptr就是繼承類的 vfptr啦。因此,通過基類指標呼叫虛函式的時候就找到的是繼承類的虛函式位址。呼叫的式繼承類的虛函式。如果繼承類沒有過載基類的某個虛函式,如 class bb,則繼承類就是直接繼承的基類的那個虛函式。
ok,下面來看一下類記憶體布局,使用microsoft visual studio的cl命令可以簡單看到類的記憶體布局。
即:使用命令 cl demo.cpp /d1reportsingleclasslayoutcc (cc為你想檢視的類名)可檢視類的記憶體布局。
class aa memory layout
class aa size(4):
+---
0 |
+---
aa::$vftable@:
| &a_meta
| 0
0 | &aa::fun
1 | &aa::fun1
aa::fun this adjustor: 0
aa::fun1 this adjustor: 0
class bb memory layout
class bb size(12):
+---
| +--- (base class
0 | |
| +---
4 | i
8 | j
+---
bb::$vftable@:
| &bb_meta
| 0
0 | &bb::fun
1 | &aa::fun1
bb::fun this adjustor: 0
/class c memory layout
class cc size(4):
+---
| +--- (base class
0 | |
| +---
+---
cc::$vftable@:
| &cc_meta
| 0
0 | &cc::fun
1 | &cc::fun1
cc::fun1 this adjustor: 0
cc::fun this adjustor: 0
綜上可知,類的虛函式表的結構和其基類的虛函式表結構一致。(順序一致)
如果繼承類沒有過載某個基類的虛函式,
則在繼承類的虛函式表中依然會儲存其基類的那個虛函式的位址。它是直接繼承基類的虛函式。非虛函式不出現在類的記憶體布局裡。
注 意每個類後面的size(*);這個東西。這個是說的是類占用多少記憶體,即使用sizeof(類變數)得到的結果就是這個size。我們來看 看,class aa的size是4,咦,明明該是1(如果沒有虛函式的類中沒有成員變數sizeof結果就是1,不要問我,microsoft visual studio這麼說的)怎麼是4咧,細心的童鞋可能已經發現,剛剛談到了class a還有乙個隱藏的成員指標變數vfptr。因此,class b的size是12就不足為奇了。ok就這樣吧,鄙人不才,有不對之處請各位童鞋多多指正。謝謝
參考: 1. http://c.chinaitlab.com/cc/basic/200908/790967.html
2.以前看過的n多書
C 原理剖析之虛函式表
最近在看c 的一些相關的機制,再加上剛看了陳皓大神的早期關於虛函式表的部落格,便自己動手通過程式設計了解了下虛函式表的原理。c 是通過虛函式來實現多型的的機制。我們可以通過將父類的指標指向子類的例項,如base b new derive 如此一來,如果子類derive中過載了父類中的乙個函式h 那麼...
虛函式的內部實現原理深入剖析
今天學c 多型時,對虛函式實現原理有些疑惑。然後爬了很多文,看了很多教程。經過一系列研究,以下是我的理解 多型是c 物件導向三大特性之一 多型分為兩類 靜態多型和動態多型區別 注意 請按照編號順序檢視 說明 include includeusing namespace std 動物類 class a...
C 虛函式實現原理
c 中的虛函式的作用主要是實現了多型的機制。基類定義虛函式,子類可以重寫該函式。每個類物件新增乙個成員,該成員中儲存了乙個指向函式位址陣列的指標,稱為虛表指標 vptr 該陣列稱為虛函式表 virtual function table,vtbl 即,每個類使用乙個虛函式表,每個類物件用乙個虛表指標。...