返回

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字节

特别声明:以上内容(图片及文字)均为互联网收集或者用户上传发布,本站仅提供信息存储服务!如有侵权或有涉及法律问题请联系我们。
举报
评论区(0)
按点赞数排序
用户头像
精选文章
thumb 中国研究员首次曝光美国国安局顶级后门—“方程式组织”
thumb 俄乌线上战争,网络攻击弥漫着数字硝烟
thumb 从网络安全角度了解俄罗斯入侵乌克兰的相关事件时间线