C++中对象的内存布局(三)

给出这样的重复继承:

image.png

(一)、直接继承,没有虚函数存在时,书写如下:

class CA
{……};
class CB:public CA
{……};
class CC:public CA
{……};
class CD:public CB,public: CC
{……};

查看内存布局如下:

image.png

由于B和C都继承了A,所以在D中重复出现了A中的成员变量,所以当试图访问间接基类中的成员变量时,务必要加上作用域

当把类CA、CB、CC、CD中的函数都写成虚函数时,依旧还是重复出现,如下图:


image.png

(二)、虚继承

书写代码如下:(将继承关系改为虚继承)

class CA
{
public:
    CA(int a=10):ma(a){}
    virtual void a(){cout<<"CA::a()"<<" ";}
    virtual void aa(){cout<<"CA::aa()"<<" ";}
    virtual void aaa(){cout<<"CA::aaa()"<<" ";}
public:
    int ma;
};
 
class CB:virtual public CA
{
public:
    CB(int b=20):mb(b){}
    virtual void a(){cout<<"CB::a()"<<" ";}
    virtual void bb(){cout<<"CB::bb()"<<" ";}
    virtual void bbb(){cout<<"CB::bbb()"<<" ";}
protected:
    int mb;
};
class CC:virtual public CA
{
public:
    CC(int c=30):mc(c){}
    virtual void a(){cout<<"CC::a()"<<" ";}
    virtual void cc(){cout<<"CC::cc()"<<" ";}
    virtual void ccc(){cout<<"CC::ccc()"<<" ";}
protected:
    int mc;
};
class CD:public CB,public CC
{
public:
    CD(int d):md(d){}
    virtual void a(){cout<<"CD::a()"<<" ";}
    virtual void bb(){cout<<"CD::bb()"<<" ";}
    virtual void ccc(){cout<<"CD::ccc()"<<" ";}
    virtual void d(){cout<<"CD::d()"<<" ";}
protected:
    int md;
};

对于虚继承,可以避免重复继承的作用,打印其内存布局看看情况:


image.png

可以看到在虚继承下,前面所说的出现两次的成员变量和成员函数出现了一次,且都放在了内存布局中的最后面,那怎么找到呢?就是从图中看到的vbptr指针,它指向vbtable,vbtable中记录了两行数字,据分析,可以做出总结:


image.png

根据以上内存布局,做出打印:

typedef void (*Function)(void);//函数指针
int main()
{
    CD d(40);
    long** pd=(long**)(&d);//将对象d的地址强转成为二级指针。
    Function Fun=NULL;
 
    
    cout<<"[0]"<<" "<<"CB::_vfptr"<<endl;
    for(int i=0;i<3;++i)//打印类CB下的vfptr指向的vftable
    {
        Fun=((Function*)pd[0])[i];
        cout<<"    "<<"["<<i<<"]"<<" ";
        Fun();
        cout<<pd[0][i]<<endl;
    }
    cout<<"[1]"<<" "<<"CB::_vbptr"<<endl;
    for(int i=0;i<2;++i)//类CB下vbptr指向的vbtable
    {
        cout<<"       "<<pd[1][i]<<endl;
    }
    cout<<"[2] CB::mb="<<((long*)(&d))[2]<<endl;//CB::mb
    cout<<"[3]"<<" "<<"CC::_vfptr"<<endl;
    for(int i=0;i<2;++i)//打印类CC下的vfptr指向的vftable
    {
        Fun=((Function*)pd[3])[i];
        cout<<"    "<<"["<<i<<"]"<<" ";
        Fun();
        cout<<pd[3][i]<<endl;
    }
    cout<<"[4]"<<" "<<"CC::_vbptr"<<endl;
    for(int i=0;i<2;++i)//类CC下vbptr指向的vbtable
    {
        cout<<"       "<<pd[4][i]<<endl;
    }
    cout<<"[5] CC::mc="<<((long*)(&d))[5]<<endl;//CC::mc
    cout<<"[6] CD::md="<<((long*)(&d))[6]<<endl;//CD::md
    cout<<"[7] (vtordisp for vbase CA)="<<((long*)(&d))[7]<<endl;
    cout<<"[8]"<<" "<<"CA::_vfptr"<<endl;
    for(int i=0;i<3;++i)//类CA下vbptr指向的vbtable
    {
        cout<<"    "<<"["<<i<<"]"<<" ";
        Fun=((Function*)(pd[8]))[i];
        
        Fun();
        cout<<pd[8][i]<<endl;
    }
    cout<<"[9] CA::ma="<<((long*)(&d))[9]<<endl;//CA::ma
 
    return 0;
}

打印结果如下:


image.png

现在就可以画出内存布局:


image.png

总结:

1、当出现重复继承时(像这种菱形继承),会重复出现间接基类的数据,一般为了避免重复出现,因此采用虚继承(虚拟继承)。

2、在虚拟继承下,编译器将重复出现的数据放在了这个内存布局的最后边(当然有vfptr时还是依据vfptr优先级高放),并且为了标记它,在每个直接父类的作用域下有了vbptr指针,用来指向存放重复出现数据相对的偏移的vbtable。

3、在查看内存布局时,看到了下标七号存放着一个0,也就是上面标记的vtordisp for vbase CA,为什么是0?不知道为什么,也没查出结果,我猜想是为了做区分吧。

https://blog.csdn.net/zhuoya_/article/details/80055541

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容