C++ 内存模型——虚表(vtbl)的访问

C++ 对象模型
C++ 对象模型(二)

前面的文章中,我们说到,C++ 对动态多态(动态绑定,函数重载、模板、运算符重载:静态编译期绑定)的支持是通过虚表来实现的,C++ 编译器会为包含 virtual 成员函数的类,在其所占内存空间的前4个字节(刚好是指针的大小)提供一个指向虚表的指针(指向虚表,也即其存放的虚表的地址)。

是否果真如此呢?我们接下来试着验证一下(注:以下做法有违面向对象封装性的要求,属于不安全的访问,除非演示、查看 C++ 内存模型,慎用)。


#include <iostream>
using namespace std;

class Base
{
public:
    Base() :_x(0){}
    virtual void foo1() { cout << "Base::foo1()" << endl; }
    virtual void foo2() { cout << "Base::foo2()" << endl; }
private:
    int _x;
};

class Derived :public Base
{
public:
    void foo2() { cout << "Derived::foo2()" << endl; }
    virtual void foo3() { cout << "Derived::foo3()" << endl; }

private:
    int _y;
};

typedef void(*FUNC)();

int main(int, char**)
{
    Base b;
    long** p = (long**)&b;

    //p[0] == > 指向虚表
    //p[0][0] == > foo1()
    //p[0][1] == > foo2()
    // p[1] 表示non-static数据成员
    ((FUNC)p[0][0])();
    // 这里的访问是根据内存模型推算而来,与类成员的访问修饰符无关  
    ((FUNC)p[0][1])();
    //p[1] == > 数据成员
    cout << "===================" << endl;
    Base* pb = new Derived;
    p = (long**)pb;
    ((FUNC)p[0][0])();
                    // 子类没有重写,调用父类
    ((FUNC)p[0][1])();
                    // 子类覆盖,调用子类
    ((FUNC)p[0][2])();
                    // 子类所独有的虚函数,调用子类

    return 0;
}

继承关系中的两类(Base、Derived)各自的内存模型如下:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值