1.多重继承的概念:一个类有两个或者更多个基类
形式为 class <类名>:<访问属性> class <类名>,<访问属性> class <类名>
如 class A:public class B,public class C
上面的定义中,如果B和C都有print函数,这时A类的对象调用print函数,将会发生二义性,这是多重继承存在的缺陷,避免这种二义性,可以用域访问符::,如A类的对象a访问B类中的print函数,可以用a.B::print().
2.在多重继承下,一个基类可以再派生层次中出现多次,比如下面的继承结构
A类派生 B和C类,D类继承自B类和C 类。
D类的对象沿着A—B—D的方向有了A的一份副本,沿着A—C—D的方向有了第二个副本,这时在调用某些成员时难免会出现二义性,C++引入了虚继承机制来解决这个问题,将A类声明为B类和C类的虚基类,这样D类的对象只会含有A类的一个副本。
虚基类的声明要加上virtual关键字,方式如下:
Class B:virtual pubic A
Class C:virtual public A
在回到刚刚讲到的二义性问题,如果A类有成员x,那么D类的对象在访问成员x时,可以完全消除二义性吗?并不能完全消除。这里要分三种情况
(1)如果x仅仅在A类中出现,调用成员x将没有二义性
(2)如果x成员在A类中和B类中同时出现,D类对象调用的将是B类的成员x,这说明派生类的实例优先级高于共享虚基类的实例
(3)如果x成员在B类中和C类中同时出现,D类对象调用成员x时,将会出现二义性
下面是说明的代码:
# include <iostream>
using namespace std;
class Base
{
public:
Base(int t):x(t){}
void print(){cout<<x<<endl;}
int get(){return x;}
int x;
};
class Der1:virtual public Base
{
public:
Der1(int t):Base(t){}
void print(){cout <<x<<endl;}
int addx(){return ++x;}
};
class Der2:virtual public Base
{
public:
Der2(int t):Base(t){}
int addx(){return ++x;}
};
class Der3:public Der1,public Der2
{
public:
Der3(int t):Base(t),Der1(t),Der2(t){} //虚继承中,底层派生类初始化所有基类
};
int main()
{
Der3 p(4); //定义派生类的对象
p.print(); //print 出现在基类Base和Der1中,会选择调用Der1的版本
cout<<p.get()<<endl;//get()仅仅出现杂虚基类Base中,不会引起二义性
//cout<<p.addx()<<endl;// addx() 出现在基类Der1和Der2中,会引起二义性
cin.get();
return 0;
}
3.虚继承中的构造顺序和析构顺序
在上面四个类ABCD的继承层次中,构造函数的调用顺序为A—B—C—D ,析构函数的调用顺序刚好相反。
在更复杂的继承结构中,虚基类和普通基类同时出现,虚基类的调用优先级高于非虚基类,不管虚基类位于什么继承层次,虚基类的构造函数在非虚基类之前调用。