c++继承(单继承,多继承,菱形继承和虚继承)详解

下面我将从继承实例(代码 )继承对象模型原理来分析继承。
单继承
模型
这里写图片描述
代码

class A
{
public:
    int _a;
};
class B:public A
{
public:
    int _b;
};
int main()
{
    B b;
    b._a = 0;
    b._b = 1;

    return 0;
}

代码分析:
这里写图片描述
多继承
模型
这里写图片描述

class A
{
public:
    int _a;
};
class B
{
public:
    int _b;
};
class C :public A, public B
{
public:
    int _c;
};
int main()
{
    C c;
    c._a = 0;
    c._b = 1;
    c._c = 2;

    return 0;
}

代码分析
这里写图片描述
多继承我们要注意一个问题:当继承列表发送变化时,那么我们的对象模型也将发生改变。
原则:继承列表先写谁,谁将在低地址。和谁的类在不在前面无关,只于几次列表有关
我将 class C :public A, public B换成class C :public B, public A那么c的对象模型将变成下面的格式
这里写图片描述
菱形继承
模型
这里写图片描述

class A
{
public:
    int _a;
};
class B:public A
{
public:
    int _b;
};
class C:public A
{
public:
    int _c;
};
class D:public B,public C
{
public:
    int _d;
};

int main()
{
    D d1;
    d1._a = 0;
    d1._b = 1;
    d1._c = 2;
    d1._d = 4;


    return 0;
}

代码将不能编译通过,提示
这里写图片描述
当屏蔽//d1._a = 0;后可以通过编译,但是我们将无法访问父类的成员。所以我们迫切需要解决它的办法。
我们仔细看看报的错误,访问对象不明确,于是我们可以通过下面的方法进行访问_a:

d1.B::_a = 3;
d1.C::_a = 0;

这样就可以通过编译了。
下面我们研究下它的对象模型
这里写图片描述
我们通过计算可以得到对象d1的大小为20字节。但是对于我们来说,查找基类的成员变得困难了,有没有一种方式来解决这个问题?
于是虚继承出现了,它解决了菱形继承访问父类成员出现的二义性问题
下面我们一起来看看它是怎么解决二义性问题的:
虚继承
虚继承就是在被继承的前面加上virtual关键字
它是菱形继承的一种改进,所以它的继承方式和菱形继承一样,只是对象模型有区别。

class A
{
public:
    int _a;
};
class B:virtual public A
{
public:
    int _b;
};
class C :virtual public A
{
public:
    int _c;
};
class D:public B,public C
{
public:
    int _d;
};

int main()
{
    D d1;
    cout << sizeof(d1) << endl;
    d1._a = 0;
    d1._b = 1;
    d1._c = 2;
    d1._d = 4;


    return 0;
}

这里写图片描述
加入虚继承后d1的大小变成24字节,因为C类和B类都多了一个相对于_a的偏移量,所以多了四个字节。虚继承只有一份父类的数据,但是他在别的类中增加了四个字节来获取基类成员相对于别的类的偏移量。这样就解决了在菱形继承的二义性问题,但是它也引入了,程序性能下降的问题,这里就不做详细的说明。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值