普通函數(shù)與虛函數(shù)的區(qū)別
當(dāng)類里面沒有虛函數(shù)只有普通函數(shù)時:
當(dāng)類里面有虛函數(shù)時:
我們發(fā)現(xiàn)this指針的值和類所占的空間大小變了,也就是說當(dāng)類里面出現(xiàn)虛函數(shù)時就會增加4個字節(jié)大小的空間厨内。增加的4個字節(jié)就在類的首地址處。
編譯器運行時先檢查類里面是否有虛函數(shù)
如果有則分配4個字節(jié)的大小唯蝶,然后在檢查成員變量并分配空間,最后在執(zhí)行構(gòu)造函數(shù)遗嗽。粘我。
我們來看看增加的那4個字節(jié)到底是什么東西
class Test
{
public:
Test()
{
this->i = 2;
printf("%d\n%d\n", *(int *)this,sizeof(Test));
}
virtual void Fun1()
{
printf("調(diào)用了fun1\n");
}
virtual void Fun2()
{
printf("調(diào)用了fun2\n");
}
private:
int i;
};
int _tmain()
{
Test t;
Test *p = &t;
p->Fun1();
return 0;
}
//調(diào)用構(gòu)造函數(shù)
003224C8 lea ecx,[ebp-10h]
003224CB call 00321186
003224D0 lea eax,[ebp-10h] //將存儲this指針的地址傳給eax
003224D3 mov dword ptr [ebp-1Ch],eax
003224D6 mov eax,dword ptr [ebp-1Ch]
003224D9 mov edx,dword ptr [eax] //將this指針的值傳給edx
003224DB mov esi,esp
003224DD mov ecx,dword ptr [ebp-1Ch]
//將this指針的值解引用后傳給eax
//(也就是將當(dāng)有類里虛函數(shù)時編譯器分配的4個字節(jié)大小的地址解引用后傳給eax)
003224E0 mov eax,dword ptr [edx]
003224E2 call eax //調(diào)用this指針存的值
分析到這我們知道了 p->Fun1();這個成員函數(shù)的地址是this指針存的4字節(jié)大小的地址解引用后的值
我們現(xiàn)在論證一下
**(int **)p 這這樣做是因為this指針是一個地址 而this指針里面又存了一個4字節(jié)大小的地址
運行結(jié)果如下:
我們在看看
這就證明this指針存的地址指向一個函數(shù)地址表 我們稱這個函數(shù)地址表為虛函數(shù)表。
總結(jié):當(dāng)一個類出現(xiàn)虛函數(shù)時 那么編譯器會在類的首地址(this指針)分配一個4字節(jié)大小地址 無論虛函數(shù)有多少個痹换,編譯器都只分配一個4字節(jié)的大小的地址征字,這個地址指向了虛函數(shù)表
虛函數(shù)表的大小取決于虛函數(shù)的數(shù)量。
若是有錯誤之處 還請指明娇豫!多謝