1.对象和指针调用虚函数
class Base
{
public:
void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
};
void TestMethod()
{
Base base;
base.Function_1();
00401090 8D 4D FC lea ecx,[ebp-4]
00401093 E8 9F FF FF FF call @ILT+50(Base::Function_1) (00401037)
base.Function_2();
00401098 8D 4D FC lea ecx,[ebp-4]
0040109B E8 65 FF FF FF call @ILT+0(Base::Function_2) (00401005)
Base* pb = &base;
pb->Function_1();
004010A6 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010A9 E8 89 FF FF FF call @ILT+50(Base::Function_1) (00401037)
pb->Function_2();
004010AE 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010B1 8B 11 mov edx,dword ptr [ecx]
004010B3 8B F4 mov esi,esp
004010B5 8B 4D F8 mov ecx,dword ptr [ebp-8]
004010B8 FF 12 call dword ptr [edx]
}
总结:
1. 通过对象调用时,virtual函数与普通函数都是E8 Call
2. 通过指针调用时,virtual函数是FF Call,也就是间接Call
2.虚函数表
class Base
{
public:
int x;
int y;
virtual void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
};
pb->Function_1();
0040D9E3 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040D9E6 8B 11 mov edx,dword ptr [ecx]
0040D9E8 8B F4 mov esi,esp
0040D9EA 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040D9ED FF 12 call dword ptr [edx]
pb->Function_2();
0040D9F6 8B 45 F0 mov eax,dword ptr [ebp-10h]
0040D9F9 8B 10 mov edx,dword ptr [eax]
0040D9FB 8B F4 mov esi,esp
0040D9FD 8B 4D F0 mov ecx,dword ptr [ebp-10h]
0040DA00 FF 52 04 call dword ptr [edx+4]
总结:
- 当类中有虚函数时,会多一个属性,4个字节
- 多出的属性是一个地址,指向一张表,里面存储了所有虚函数的地址
3.验证虚函数表
class Base
{
public:
int x;
int y;
virtual void Function_1()
{
printf("Function_1...\n");
}
virtual void Function_2()
{
printf("Function_2...\n");
}
virtual void Function_3()
{
printf("Function_3...\n");
}
};
void TestMethod()
{
//查看 Sub 的虚函数表
Base base;
//对象的前四个字节就是虚函数表
printf("base 的虚函数表地址为:%x\n",*(int*)&base);
//通过函数指针调用函数,验证正确性
typedef void(*pFunction)(void);
pFunction pFn;
for(int i=0;i<3;i++)
{
int temp = *((int*)(*(int*)&base)+i);
pFn = (pFunction)temp;
pFn();
}
}
总结:
4.单继承无函数覆盖
#include <iostream>
using namespace std;
struct Base
{
public:
virtual void Function_1()
{
printf("Base:Function_1...\n");
}
virtual void Function_2()
{
printf("Base:Function_2...\n");
}
virtual void Function_3()
{
printf("Base:Function_3...\n");
}
};
struct Sub:Base
{
public:
virtual void Function_4()
{
printf("Sub:Function_4...\n");
}
virtual void Function_5()
{
printf("Sub:Function_5...\n");
}
virtual void Function_6()
{
printf("Sub:Function_6...\n");
}
};
void TestMethod()
{
Sub sub;
void (*pf)();
for(int i=0;i<6;i++)
{
pf = (void (*)())(((int*)*((int*)&sub))[i]);
pf();
}
}
int main()
{
TestMethod();
}
说明6个函数在同一个表里,并且按照1,2,3,4,5,6排列,先父类再子类
5.单继承有函数覆盖(打印Sub对象的虚函数表)
#include <iostream>
using namespace std;
struct Base
{
public:
virtual void Function_1()
{
printf("Base:Function_1...\n");
}
virtual void Function_2()
{
printf("Base:Function_2...\n");
}
virtual void Function_3()
{
printf("Base:Function_3...\n");
}
};
struct Sub:Base
{
public:
virtual void Function_1()
{
printf("Sub:Function_1...\n");
}
virtual void Function_2()
{
printf("Sub:Function_2...\n");
}
virtual void Function_6()
{
printf("Sub:Function_6...\n");
}
};
void TestMethod()
{
Sub sub;
void (*pf)();
for(int i=0;i<4;i++)
{
pf = (void (*)())(((int*)*((int*)&sub))[i]);
pf();
}
printf("%d",sizeof(Sub));
}
int main()
{
TestMethod();
}
子类会覆盖父类的同名函数,且虚函数表地址在ebp-8,为啥不是ebp-4?理由未知