C++ 使用子类对象推算虚函数地址并调用
发布时间:2022-10-08 10:22:32 467
相关标签:
这是一篇关于讲解关于虚函数内存模型的问题,从内存层面,推演虚函数指针和虚函数表
1.结论总结
- [] 在windows平台,对象的首地址即是vPtr所在,对vPtr取内容,即是虚函数表的地址,将地址强转为函数指针,可以间接访问子类虚函数 - [] 子类对象的虚函数指针指向的是子类的虚函数表,且每个子类对象单独维护一个vPtr,在windows平台,位于对象的首位 - [] 虚函数表中存放的虚函数是不带类类型的普通函数
2.使用对象推算虚函数指针指向的虚函数并调用
定义一个基类指针指向子类对象,使用子类对象地址推算出虚函数指针,进而推算虚函数表地址,从而通过函数指针调用虚函数
2.1 定义与虚函数类型相同的函数指针
typedef void(*pFunc)() ; //假设虚函数返回值为void,参数类型为void
2.2 定义父类和子类
//基类
class Base
{
public:
Base() {};
virtual void fun1()
{
cout << "Base::fun1()" << endl;
}
virtual void fun2()
{
cout << "Base::fun2()" << endl;
}
virtual void fun3() {}
~Base() {};
};
//派生类
class Derived : public Base
{
public:
Derived() {};
void fun1()
{
cout << "Derived::fun1()" << endl;
}
void fun2()
{
cout << "DerivedClass::fun2()" << endl;
}
~Derived() {};
};
2.3 定义对象并推算
int main(void)
{
// 基类指针指向派生类实例
Base* pt = new Derived();
//接收该对象,使用void *接收,便于重新划分内存
void* obj = pt;
cout << "在Windows平台,vPtr存在对象的首位,开始计算" << endl;
cout << "sizeof(unsigned long)" << sizeof(unsigned long) << endl;
//先将obj的无类型未知长度的内存地址划分转为(unsigned long*),这样可以明确访问obj的前四个字节,
unsigned long* vAddr = (unsigned long*)obj; //vAddr就是vPtr
//对虚函数指针,取内容,取到的就是虚函数表的地址
unsigned long vTableAddr = (*vAddr); //取到的是虚函数表的地址
//将整数类型转为地址
unsigned long* vFunc_first = (unsigned long*)(*vAddr);
//将地址转为函数指针
pFunc xFunc = pFunc(*vFunc_first);
//使用函数指针访问第一个虚函数
xFunc();
//使用函数指针访问第二个虚函数
pFunc yFunc = pFunc(*(vFunc_first + 1));
yFunc();
delete pt;
system("pause");
return 0;
}
- [] 从void*解算vPtr和平台有关系。32位系统指针为4字节,64位系统指针为8字节
文章来源: https://blog.51cto.com/u_13030942/5429739
特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报