多態的實現分為靜態多態和動態多態,靜態多態主要靠函數重載,動態多態主要靠虛函數
當類中聲明了虛函數之後,該類的內存映像會獲得一個虛表指針,叫做_vfptr指向該類的虛表,下面的我測試使用的類圖(有的沒必要的東西沒有寫)
這裡恰好還是一個菱形繼承,但是就像我之前說的虛繼承和虛表關系不大,所以單繼承也是可以測試的
其中高亮的部分就是虛表指針,用內存窗口就可以看到虛表中存放的東西了,每一個多態類的對象都有一個自己的虛表指針,並且多繼承的對象會有多個_vptr指針
m和m1的_vptr指向同一個虛表
多繼承對象有更多的_vfptr指向不同的虛表
這裡我們雖然看到的是_vfptr是放在m對象的最後,但是在內存中_vfptr是存放在m內存空間一開頭的地方!!如果我們想要強取虛表並且把虛表中的函數指針打印出來看看的話,只要取m的地址(就是一開始的頭地址)就可以了,=(雖然一般人不會這麼做,如果只是想看看的話),如果還想打印其他的虛表的話就把指針偏移一下,_vfptr就是指向虛表的指針,就相當於指向一個函數指針數組的第一個元素指針,獲得了這個指針之後就可以像訪問數組一樣訪問這個虛表了
如下圖所示對象m地址空間一開始就是虛表指針_vfptr,緊接著是虛繼承表指針_vbptr(要區分開!)(虛繼承表詳解看菱形繼承那篇博客)
強取虛表打印代碼
void PrintVtable(int *vTable)
{
for (int i = 0; vTable[i] != 0; i++)
{
printf("%x\n", vTable[i]);
FUNC f = (FUNC)vTable[i];
f();
}
}//因為指針和int型變量都是4個字節,所以我們用整型變量來存放地址
int *vTable = (int *)(*(int *)&m);
PrintVtable(vTable);