环境: VS2019, Debug x86编译器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class Base {
public:
virtual void func1() = 0;
virtual void func2() = 0;
};
class Drived : public Base {
public:
virtual void func1()
{
printf("Drived::%s()\n", __func__);
}
virtual void func2()
{
printf("Drived::%s()\n", __func__);
}
};
typedef void(*Fun)();
int main()
{
Base* pBase = new Drived();
pBase->func1();
// printf("sizeof(long) = %zu\n", sizeof(long));
printf("0x%p\n", pBase);
printf("0x%p\n", (int*)pBase);
int ptr = (*(int*)pBase); // vfptr的地址
Fun pF = (Fun)(*((int *)ptr + 1));
pF();
delete pBase;
return 0;
}
运行结果:
如果是在x64编译器环境下则把int *换成long long *, 因为两者的偏移量不一致
我在x64环境下long的字节为4
__vfptr是函数指针数组,在x64下指针是8个字节,所以vfptr数组内的元素各占8字节,故需要使用long long指针,这样+1才会偏移8个字节,如果为int *,则+1偏移量是4
下面是传参函数环境与上一致
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
class Base {
public:
virtual void func1() = 0;
virtual void func2(int num) = 0;
};
class Drived : public Base {
public:
virtual void func1()
{
printf("Drived::%s()\n", __func__);
}
virtual void func2(int num)
{
printf("Drived::%s(%d)\n", __func__, num);
}
};
typedef void(__stdcall *Fun)(int);
// 不太理解此处为何需要加stdcall
// 参考https://blog.csdn.net/sky1718/article/details/51004758加上后运行不报错了
int main()
{
Base* pBase = new Drived();
pBase->func1();
// printf("sizeof(long) = %zu\n", sizeof(long));
// printf("0x%p\n", pBase);
printf("0x%p\n", (int *)pBase);
int ptr = (*(int *)pBase);
Fun pF = (Fun)(*((int *)ptr + 1));
pF(10);
delete pBase;
return 0;
}
运行结果:
题外话
如果把Base的public改为private,那么使用vfptr仍然可以调用到private的函数
如果你只是把Drived的public改为private,则pBase->func1()不会报错,因为func1继承过来的就是public