C++三特性之继承(2)

菱形继承、虚继承、虚基类和虚继承下的内存模型


一、 菱形继承

        菱形继承,是指派生类D的两个或多个直接基类B、C,继承自同一个或多个间接基类A,那么在派生类D中存在继承自间接基类A的两份成员变量。

        这种情况下很容易出现命名冲突的情况。比如基类A中存在一个成员变量int a,在派生类D中使用的时候必须要利用类名和域解析符去做强调。

        

void seta(int a){ B::m_a = a; }
void setb(int b){ C::m_b = b; }

二、虚继承

1.为了解决命名冲突和数据冗余问题,引入虚继承

        此时需要将两个直接基类B、C继承间接基类A方式上加上virtual,使得在派生类中只保留一份间接基类的成员

//间接基类A
class A{
protected:
    int m_a;
};
//直接基类B
class B: virtual public A{  //虚继承
protected:
    int m_b;
};
//直接基类C
class C: virtual public A{  //虚继承
protected:
    int m_c;
};
此时,共享基类A被称为虚基类,

2.虚继承成员变量

        因为在虚继承的最终派生类中只保留了一份虚基类的成员,所以该成员可以被直接访问,不会产生二义性。此外,如果虚基类的成员只被一条派生路径覆盖,那么仍然可以直接访问这个被覆盖的成员。但是如果该成员被两条或多条路径覆盖了,那就不能直接访问了,此时必须指明该成员属于哪个类。

3.虚继承构造函数与初始化

        不存在虚继承时,初始化仅会调用直接基类的构造函数,但是存在虚继承时,会调用间接基类的构造函数。

        在最终派生类的构造函数调用列表中,不管各个构造函数出现的顺序如何,编译器总是先调用虚基类的构造函数,再按照出现的顺序调用其他的构造函数;而对于普通继承,就是按照构造函数出现的顺序依次调用的。

4.虚继承的内存模型

        对于普通继承的方式,obj_a、obj_b、obj_c、obj_d 的内存模型如下所示:


        A 是最顶层的基类,在派生类 B、C、D 的对象中,A 类子对象始终位于最前面,偏移量是固定的,为 0。b1、b2 是派生类 B 的新增成员变量,它们的偏移量也是固定的,分别为 8 和 12。c1、c2、d1、d2 也是同样的道理。

        对于存在虚继承的内存模型,大部分编译器会把基类成员变量放在派生类成员变量的后面,这样随着继承层级的增加,基类成员变量的偏移就会改变,就得通过其他方案来计算偏移量。

        若A是B的虚基类:


        若A是B的虚基类,B是C的虚基类:

 

        虚继承时的派生类对象被分成了两部分:

  • 不带阴影的一部分偏移量固定,不会随着继承层次的增加而改变,称为固定部分;
  • 带有阴影的一部分是虚基类的子对象,偏移量会随着继承层次的增加而改变,称为共享部分。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值