图解C++虚函数表和类对象的内存分布

 目录

1.单继承的内存分布

2.多继承的内存分布

3.菱形继承的内存分布


0.先说结论

  1. 在派生类对象的内存中,虚表指针放在最前面,和对象的地址相同。然后是成员变量,基类的成员变量在派生类的成员变量前面,基类和派生类的成员变量分别按类中的声明顺序排列。
  2. 对于多继承的情况,假如派生类有n个直接基类,那么派生类对象中就有n个虚表指针。派生类对象的内存可以划分为n+1块,首先存放第1个基类的虚表指针和成员变量,然后存放第2个基类的虚表指针和成员变量,以此类推。派生类自己的成员变量放在最后1块。
  3. 虚表中虚函数的顺序是按声明顺序排列的。基类虚函数的声明先于派生类。
  4. 派生类的虚函数和第一个直接基类共用一张虚表。并且在这张虚表中,基类的虚函数在前,派生类的虚函数在后。
  5. 如果派生类覆盖了基类的一个虚函数,那么虚表中本来存放这个基类虚函数地址的位置改为存放派生类版本的虚函数地址。

 

1.单继承的内存分布

假设继承体系如下: 

Derive对象的内存分布如下: 

代码验证:

class Base{
public:
    virtual f(){cout<<"Base::f"<<endl;}   // 被覆盖
    virtual h(){cout<<"Base::h"<<endl;}   // 不被覆盖
    int a;
};

class Derive: public Base{
public:
    virtual f(){cout<<"Derive::f"<<endl;}
    virtual g(){cout<<"Derive::g"<<endl;}
    int b;
};

int main(){
    typedef void(*Fun)(void);
    Derive d;
    int** pd = (int**)&d;   // 对象地址,也是虚表指针的地址
    cout<<"对象大小:"<<sizeof(Derive)<<endl;
    cout<<"对象地址:"<<&d<<endl<<endl;

    cout<<"虚表指针地址:"<<pd<<" "<<&pd[0]<<endl;
    cout<<"虚表地址:"<<*pd<<endl;
    for(int i=0;i<3;i++){   // 第1个虚表
        cout<<"函数指针地址:"<<&pd[0][i]<<" "
            <<"函数地址:"<<(void*)pd[0][i]<<" ";    // 不转换为指针则按十进制输出
        Fun pFun = (Fun)pd[0][i];
        pFun();
    }
    cout<<endl;

    cout<<endl<<"成员变量"<<endl;
    cou
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值