熟悉c++開發的朋友們都知道,每乙個包含虛函式的類的物件的前四個位元組(32位系統中,以下例子都是在32位系統下)的記憶體中存放著該物件的虛函式表的指標。虛函式表中依次存放著該物件的每個虛函式的位址。
舉個例子:
class testa
;
testa::testa()
testa::~testa()
void testa::testafunc()
void testa::testafunc1()
int main()
對於testa這個類的物件a來說,它在記憶體中的布局如下:
我們可以採用取記憶體的方法來獲得某乙個虛函式的指標,方法如下:
typedef void(*func) (void);
在main函式中加入以下**:
func pfunc = null;
pfunc = (func)*((int *)(*(int*)(&a)) + 0);
pfunc(); //實際呼叫的是testafunc()
pfunc = (func)*((int *)(*(int*)(&a)) + 1);
pfunc(); //實際呼叫的是testafunc1()
輸出為:
testafunc is called!
testafunc1 is called!
但是通過記憶體來取虛函式指標的方法有點繁瑣,稍微乙個不留神忘了指標轉換或者解除引用就會導致錯誤,這裡,我給大家介紹一種清晰簡單的方法來取虛函式。
如上圖所示,虛函式表其實是一塊連續的記憶體,裡面每個元素(每四個位元組)都是乙個函式指標,這樣的話,我們完全可以把它看做乙個結構體,該結構體的每個成員是乙個函式指標。
struct testa_vtpr
;
如此這樣的話,我們完全可以用以下方式來引用testa 類的虛函式
(將以下**加入main函式)
testa a;
testa_vtpr **pvtable = (testa_vtpr**)(void*)&a;
testa_vtpr *pvtpr = *pvtable;
pvtpr->hook(&a);
pvtpr->hook1(&a);
(&a)->testafunc(); //必須用指向a物件的指標來引用testafunc,否則不會去查詢虛表
(&a)->testafunc1(); //同上
程式輸出如下:
testafunc is called!
testafunc1 is called!
testafunc is called!
testafunc1 is called!
可以看到pvtpr->hook(&a); 和 (&a)->testafunc();執行的結果一樣的。
親們,你們明白了麼?
虛函式的一種替代方案
虛函式的目的是實現物件的動態繫結,但是有些情況下,可能換一種替代方案,可能會使類的設計更加穩定,易用,下面列出乙個我認為很棒的虛函式的替代方案。使用non virtual inte ce nvi 手法,它以public non virtual 成員函式包裹較低訪問性的virtual函式 class ...
一種「標準」的虛函式機制簡介
編譯器是如何針對 虛函式產生可以再執行時刻確定被呼叫函式的 呢?也就是說,虛函式實際上是如何被編譯器處理的呢?lippman在深度探索c 物件模型中的不同章節講到了幾種方式,這裡把 標準的 方式簡單介紹一下。我所說的 標準 方式,也就是所謂的 vtable 機制。編譯器發現乙個類中有被宣告為virt...
一種巧妙的記憶體池演算法 HeapBlock
在乙個簡單的gui庫中看到的演算法,非常巧妙,適用於需要頻繁分配和釋放相同大小資料塊的情況,如gui庫中的視窗結構,socket結構等,演算法額外開支極小。cpp view plain copy print?typedef dword hblockheap typedef unsigned char...