前言
- 之前我们面对的都是一对一的单继承,那么我们这次来看一下多继承以及菱形继承吧~~~
- 环境:VS2019版本
1、单继承和多继承
1.1、概念
1.1.1、单继承
单继承:一个子类只有一个直接父类时,成这种继承关系为单继承
class Person
{
};
class Student:public Person//Student类直接单继承Person类
{
};
class PostGraduate:public Student//PostGraduate类直接单继承Student类
{
};
以上代码均属于单继承关系
图形表示形式:
1.1.2、多继承
多继承:一个子类有两个或两个以上的直接父类时,称这种继承关系为多继承
class Student
{
public:
int _s;
};
class Teacher
{
public:
int _t;
};
class Assistant:public Student , public Teacher
//Assistant类多继承于Student类和Teacher类
{
int _a;
};
如下图则是一种多继承关系:
注:
- 1.再多继承情况下,子类继承每个基类的继承访问权限不能少!!!(否则编译器将视为默认继承权限:private)
以实例代码为例(Teacher类前未显示public继承权限):
- 2.多继承情况下,各个类的数据的存储顺序与继承列表中的顺序保持一致
以实例代码为例
int main()
{
Assistant a;
a._s = 1;
a._t = 2;
a._a = 3;
return 0;
}
由此也可得到多继承的对象模型为:
2、菱形继承
2.1、概念
菱形继承:菱形继承是多继承的一种特殊情况,也可视为单继承和多继承的结合
class B {
public:
int _b;
};
class C1 :public B
{
public:
int c1;
};
class C2 :public B
{
public:
int c2;
};
class D :public C1, public C2
{
int _d;
};
如下图:
2.2、 存在的问题
以上述实例代码为例
当底层子类对最顶层的基类成员赋值将出现不明确问题!!
原因:C1和C2类都继承了B类中的成员_b,因而子类D类对象d在对_b赋值时无法判断是对C1类中的_b赋值还是对C2类中的_b赋值。
- 从中也可看出菱形继承中所存在的数据冗余以及二义性的问题
2.3、解决方法
- 1.通过访问限定符号的方式对各个基类继承的同名成员进行赋值
访问限定符号方式: 基类 + :: + 同名成员
由此可得菱形继承对象模型为:
- 2.通过菱形虚拟继承的方式(让最顶层基类成员在子类d对象中只储存一份)
//virtual 虚拟继承标识符
class B {
public:
int _b;
};
class C1 :virtual public B//C1虚拟继承自B
{
public:
int c1;
};
class C2 :virtual public B//C2虚拟继承自B
{
public:
int c2;
};
class D :public C1, public C2
{
public:
int _d;
};
int main()
{
D d;
d.c1 = 1;
d.c2 = 2;
d._b = 3;
d._d = 5;
return 0;
}
通过内存监视窗口,细心的铁铁可以发现d对象成员的_d加载到内存的最下面(但这其实也符合之间将的普通继承的对象模型);
注意啦,在c1和c2成员的上面分别有一个地址,那么这个地址又是干什么用的呢???
- 而这也便是虚拟继承的特性啦!!!
2.3.(1)虚拟继承
1. 对象模型
- 上述图形,也展示了此刻的构造函数,没有,编译器则一定会提供默认构造函数,有,编译器也会对其进行修改(对其前四个字节进行赋值操作-----虚表指针)
2.实例展示
如上述实例的菱形虚拟继承代码:
从内存上查看这两个虚基表指针的内容:
由此综上,可得实例代码的对象模型为:
注意:菱形虚拟继承主要用于解决菱形继承的二义性
总结
以上就是今天要讲的内容,本文主要讲了单继承,多继承以及菱形继承的概念,对象模型,以及其在VS2019上的展示。当然本文重点也当然是菱形虚拟继承啦~~~~
- 最后感谢各位铁铁们的点击与观看
- 当然若有不准确的地方,也希望请各位大佬加以指点,感谢~~~
- 当然,铁铁给予的一份小小的关注,都将成为我不懈的动力!!!