在上篇博客继承《一》中我们所了解的继承全部都是单继承,而我们现在来看继承的其他种类。
一:多继承:
那什么是多继承?我们把一个派生类有两个或者有两个以上的基类的继承称之为多继承。
举一个例子:
#include<iostream>
using namespace std;
class B1
{
public:
int _b1;
};
class B2
{
public:
int _b2;
};
class C :public B1, public B2
{
public:
int _c;
};
int main()
{
C c;
c._b1 = 10;
c._b2 = 20;
cout << sizeof(C) << endl;
cout << c._b1 << endl;
cout <<c._b2 << endl;
return 0;
}
它的输出结果是如图所示:
它在内存中的布局是这样的:
但是如果在继承的时候把B1与B2的位置换过来,那么他们在布局中的位置也将会换过来。
二:菱形继承:
先来看一个程序,了解一下什么是菱形继承。
#include<iostream>
using namespace std;
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
{
public:
int _d;
};
int main()
{
D d;
d._b = 10;
d._c1 = 20;
d._c2 = 30;
cout << sizeof(D) << endl;
cout <<d. _b << endl;
cout <<d. _c1 << endl;
cout <<d._c2 << endl;
}
这个程序会发生错误,因为当程序运行到d._b的时候,程序不知道需要访问C1中的继承的_b还是C2中继承的_b,而这就是菱形继承所面临的问题:二义性。所以你在访问_b的时候就需要它的作用域,即把程序改成:
int main()
{
D d;
d.C1::_b = 10;
d._c1 = 20;
d._c2 = 30;
cout << sizeof(D) << endl;
cout << d.C1::_b << endl;
cout <<d. _c1 << endl;
cout <<d._c2 << endl;
}
这个时候程序运行的结果就是:
而除了上面所说的加作用域解决二义性之外还有一种方法,那就是,虚拟继承。
三:虚拟继承:
那什么是虚拟继承?虚拟继承解决了菱形继承中的二义性和浪费空间的问题。
我们继续以上面的程序为例子进行分析,它的虚拟继承程序为:
#include<iostream>
using namespace std;
class B
{
public:
int _b;
};
class C1:virtual public B
{
public:
int _c1;
};
class C2:virtual public B
{
public:
int _c2;
};
class D :public C1, public C2
{
public:
int _d;
};
int main()
{
D d;
d._b = 10;
d._c1 = 20;
d._c2 = 30;
cout << sizeof(D) << endl;
cout << d._b << endl;
cout <<d. _c1 << endl;
cout <<d._c2 << endl;
}
它的输出为:
那为什么虚拟继承比菱形继承多了4个字节?
我们来看程序的内存,并分析:
所以虚拟继承需要借助偏移量的表格来访问基类的元素