• C++学习之路: 虚继承的内存的模型


    写给出结论:

    1.类大小计算遵循结构体对其原则

    2.类的大小与数据成员有关,与成员函数无关

    3.类的大小与静态数据成员无关

    4. 虚继承对类的大小影响

    5.虚函数对类的大小影响

    研究背景)

    我们以这个钻石型继承来研究下,虚继承后派生类DD的内存分布,先说原理和推测,来理解编译器的处理是如何在内存上体现的。

    保持我们一贯的做风。

    image

    #include <iostream>
    using namespace std;
    
    
    class BB
    {
    public:
        int bb_;
    };
    
    class B1 : virtual public BB
    {
    public:
        int b1_;
    };
    
    class B2 : virtual public BB
    {
    public:
        int b2_;
    };
    
    class DD : public B1, public B2
    {
    public:
        int dd_;
    };
    
    int main(void)
    {
        cout<<sizeof(BB)<<endl;
        cout<<sizeof(B1)<<endl;
        cout<<sizeof(DD)<<endl;
    
        B1 b1;
        long** p;
        
        cout<<&b1<<endl;
        cout<<&b1.bb_<<endl;
        cout<<&b1.b1_<<endl;
    
        p = (long**)&b1;
        cout<<p[0][0]<<endl;
        cout<<p[0][1]<<endl;
    
        DD dd;
        cout<<&dd<<endl;
        cout<<&dd.bb_<<endl;
        cout<<&dd.b1_<<endl;
        cout<<&dd.b2_<<endl;
        cout<<&dd.dd_<<endl;
        p = (long**)&dd;
        cout<<p[0][0]<<endl;
        cout<<p[0][1]<<endl;
        cout<<endl;
        cout<<p[2][0]<<endl;
        cout<<p[2][1]<<endl;
    
        BB* pp;
    
        pp = &dd;
        pp->bb_;        // ͨ¹ý¼ä½Ó·ÃÎÊ£¬ÕâÐèÒªÔËÐÐʱµÄÖ§³Ö
    
        return 0;
    }

    结果打印

    4
    12
    24
    0xbfacd81c
    0xbfacd824
    0xbfacd820
    0
    134515772
    0xbfacd804
    0xbfacd818
    0xbfacd808
    0xbfacd810
    0xbfacd814
    12
    -8
    
    134515700
    134515740

    根据结果,我们可以把几个类的内存分布画出来

    @B1的内存分布,可以通过照相记忆法。

    有以下特点

    image

    1。 一般来说编译器都会把虚继承的基类放置在内存底部,和构造顺序是一致的,在小端机上是

    高地址存放低字节,所以先构造bb_基类放置在底部。然后构造自身是B1

    空白处世虚基类表指针,也占据4个字节

    image

    vbptr虚基类指针指向一个虚基类表,这个表记录着两个偏移量,

    已在图上标注,*(指针和本地址的差) *(指针和虚基类的差),大家自己减一下就可以算出偏移量分布式0和8;

    @DD对象:多虚基类继承下的内存分布

    image

    可以看的出内存分布和和继承,与构造顺序的关系,基类总是先被构造,继承离最远派生类越远,越先构造,所以看到,基类BB最先被构造,然后是B2,最后是B1。

    当B1构造结束,那么整个DD类便构造完成了

    结论:通过派生类指针访问虚基类数据成员,需要在运行时动态的找到偏移地址,

    数据间接访问。

  • 相关阅读:
    【java】jfairy和java-faker假数据利器
    【Spring boot】【gradle】idea新建spring boot+gradle项目
    【mac】mac上使用brew 安装速度慢/每次使用brew 都会卡在updating homebrew不动/更换homebrew的镜像源
    【gradle】mac上安装gradle
    【mac】mac上安装JDK
    如何解决ajax跨域问题(转)
    java实现点选汉字验证码(自己修改后的)
    AES加解密
    java随机打乱集合顺序
    利用StringEscapeUtils对字符串进行各种转义与反转义(Java)
  • 原文地址:https://www.cnblogs.com/DLzhang/p/4732293.html
Copyright © 2020-2023  润新知