C++菱形继承以及解决方法--虚继承 虚基表

文章介绍了C++中菱形继承导致的二义性问题,以及如何通过虚继承来解决这一问题。虚继承确保了基类的实例只有一份,避免了内存中的重复。同时,文章强调了虚基表的作用,它存储了指向基类实例的指针,并讨论了组合在代码复用中的优势,建议在设计时优先考虑组合而非多继承。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

菱形继承形成原因

多继承,呈菱形状
在这里插入图片描述

菱形继承代码:

class A 
{
public:
    A() {}
    int _a ;
};
class B :public A 
{
public:
    //会存在父的int a;
    B() {}
    int _b ;
};
class C :public A 
{
public:
   //会存在父的int a;
    C() {}
    int _c ;
};
class D :public B,public C 
   
{
public:
   //会存在父的int a;    问题来了这个a是  父亲b中的a 还是 父亲c中的a -- 二义性;
    
   //父的int b;
   //父的int c;
    D() {}
    int _d ;
};
int main()
{
    
   
    D d;
    d.B::_a = 1;
    d.C::_a = 2;
    d._b = 3;
    d._c = 4;
    b._d = 5;
    cout << d._a << endl;//报错  提示b.a具有二义性
    return 0;

}

出现二义性变量的内存布局

在这里插入图片描述

可以看到上图中紫色框两部分,是出现二义性的两份A::_a变量,编译器无法自主确定需要用哪一个,可以d::A_a 或者 d::B_a这样使用;

应对方案

虚继承 vitrual

vitrual修饰使派生类出现二义性的父类继承部分(菱形的腰部)

class A 
{
public:
    A() {}
    int _a ;
};
class B :virtual public A //virtual修饰
{
public:
    //父的int a;
    B() {}
    int _b;
};
class C :virtual public A  //virtual修饰
{
public:
   //父的int a;
    C() {}
    int _c ;
};
class D :public B,public C 
   
{
public:

    //自己的 int a;(二义性的父亲继承经virtual修饰)
   //父的int b;
   //父的int c;
    D() {}
    int _d;
};
int main()
{
    
    D d;
    d.B::_a = 1;
    d.C::_a = 2;
    d._b = 3;
    d._c = 4;
    b._d = 5;
    cout << d._a << endl;//没问题,输出2,这个2是D类成员通过继承,使得d自己独有且只有一份的 A::_a成员变量;
    return 0;
}

解决二义性变量内存布局–虚基表

在这里插入图片描述

可以看到原先存放两个二义性数据A::a和B::a的位置,变成了一个地址?

这个两个地址就叫虚基表指针

通过对虚基表的进一步内存研究,发现了虚基表紧着得下一个位置存放了一个偏移量,这个偏移量是存放该虚基表指针的内存位置,与当前派生类独有一份的成员变量_a之间的偏移长度;

这样我们直接使用d::a的时候,因为独有一份,也不会出现数据二义性的问题了;

注意,这和多态中的虚表(虚函数表两回事)

其次,虚基表的指针,经过测试,也是某个多继承派生类的多对象共用的;

eg: D d1,d2; 其中d1,d2两个对象 上图的这两张虚基表指针是一样的,原因很简单,D类类型都一样,那么某个位置起,到另一个相对位置偏移量肯定是固定的!

(同类型的虚表指针也如此,复用节省空间嘛)

感悟

继承,多态无疑为我们创造了很多的价值,但是像菱形继承这种弊端也是存在的,本质是多继承而引起的问题,在一些语言禁止了多继承的行为,总之有利有弊,虽然C++允许了多继承,但还是尽量别写多继承这种模式,复杂度和出现问题的概率都很大;

关于代码复用等的另一种关系-组合

继承是每个派生类都能相对于继承is-a的关系; 每个派生类对象都是一个基类对象; 耦合度高

在这里插入图片描述

优先考虑组合has-a的关系; eg: 汽车-轮胎,has-a,组合(class 轮胎 作为class 车的成员嵌套) 耦合度低

在这里插入图片描述

评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我是大帅哥121

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

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

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

打赏作者

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

抵扣说明:

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

余额充值