关闭

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

标签: 继承c++实例
107人阅读 评论(0) 收藏 举报
分类:

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

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的偏移量,所以多了四个字节。虚继承只有一份父类的数据,但是他在别的类中增加了四个字节来获取基类成员相对于别的类的偏移量。这样就解决了在菱形继承的二义性问题,但是它也引入了,程序性能下降的问题,这里就不做详细的说明。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2584次
    • 积分:240
    • 等级:
    • 排名:千里之外
    • 原创:22篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类