【c++】菱形继承

单继承】:一个子类只有一个直接的父类的继承关系

这里写图片描述
多继承】:一个子类有两个或者两个以上的直接父类的继承关系
菱形继承】:
这里写图片描述

class A
{
public:
 void fun()
    {
        cout << "A::fun()" << endl;
    }
    int _a;//sizeof(A) = 4
};
class B :public A
{
public:
 void fun1()
    {
        cout << "B::fun()" << endl;
    }
    int _b;//sizeof(B) =4(A成员_a)+4+(成员_b)= 8
};
class C:public A
{
public:
void fun2()
    {
        cout << "C::fun()" << endl;
    }
    int _c;//sizeof(C) =4(A成员_a)+4+(成员_c)= 8
};
class D :public B, public   C
{
public:
void fun3()
    {
        cout << "D::fun()" << endl;
    }
        int _d;//sizeof(D)=8(szeof(B))+8(sizeof(C))+4(_d)=20
};

int main()
{
    D d1;
    d1.B::_a = 1;
    d1.C::_a = 2;
    d1._b = 3;
    d1._c = 4;
    d1._d = 5;
    cout << sizeof(D) << endl;
    system("pause");
    return 0;
}

这里写图片描述这里写图片描述菱形的二义性问题
我们看到,子类D继承了父类B的成员 _a,同时也继承了父类C的成员_a;那么问题来了,当我们给D类中的_a赋值时到底是给那个_a赋值呢?
这里写图片描述相当于A在类中有两个,这可能不是我们想要的结果,增加调用的困难,同时也会浪费内存资源。
当然,我们可以声明类域解决调用这个问题。
这里写图片描述可以看到A指向的虚函数表的位置是不一样的!即有两个实例!
虚函数表
虚函数表就是通过一块连续的内存来存储虚函数是我地址。在有虚函数的对象实例中都存在一张虚函数表,虚函数表就像一张地图,指明了实际应该调用的虚函数函数。
这里写图片描述

那么如何解决菱形二义性问题呢??——使用虚拟继承

class A
{
public:
    virtual void fun()//fun是虚函数
    {
        cout << "A::fun()" << endl;
    }
public:
    int _a;//sizeof(A) = 4(成员变量_a)+4(虚表指针) = 8
};
class B :virtual public A//B类虚继承A
{
public:
    void fun1()
    {
        cout << "B::fun()" << endl;
    }
public:
    int _b;//sizeof(B) = 8(A副本)+4(虚表指针)+4(成员变量_b) = 16
};
class C:virtual public A//C虚继承A
{
public:
    void fun2()
    {
        cout << "C::fun()" << endl;
    }
public:
    int _c;
};
class D :public B, public   C
{
public:
    void fun3()
    {
        cout << "::fun()" << endl;
    }
    public:
    int _d;//sizeof(D)=8(B副本)+8(c副本)+4(虚表指针)+4(成员_d)+4(公共的A的虚表指针) = 28
 };
int main()
{
    D d1;
    system("pause");
    return 0;
}

我们打开调试,可以看到如下:
这里写图片描述
B类和C类中的A类是同一份,既在B类中改变A,那么C类中的A也改变,说明虚继承消除了菱形的二义性问题。
小结:
可以通过虚拟继承消除二义性,但是虚拟继承的开销是增加虚函数指针

我们发现一个问题;既然B类和C类虚继承A类。同时他自己也有虚函数,那么B类和C类自己的虚表指针_vfptr呢??
这是因为在vs编译器下,他把子类本身的虚表指针没有显示出来。但是他是真真实实存在的,我们在vs的监视窗口中看不到而已。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值