要介绍虚基类的作用,首先要引出多继承的概念。
多继承(Multiple Inheritance)是指从多个直接基类中产生派生类的能力,多继承的派生类继承了所有父类的成员。
多个基类的相互交织可能会带来错综复杂的设计问题,命名冲突就是不可回避的一个问题,所以虚基类的作用就是避免了多继承时产生命名冲突。
如图:
上图的继承方式我们称为菱形继承,我们拿此图来举例说明。
类 A 派生出类 B 和类 C,类 D 继承自类 B 和类 C,这个时候类 A 中的成员变量和成员函数继承到类 D 中变成了两份,一份来自 A–>B–>D 这条路径,另一份来自 A–>C–>D 这条路径。
所以,当我们定义D类型对象后,假如类 A 有一个成员变量 a,那么在类 D 中直接访问 a 就会产生歧义,编译器不知道它究竟来自 A –>B–>D 这条路径,还是来自 A–>C–>D 这条路径。
代码如下:
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 x;
x.b=10;//正确
x.c=10;//正确
x.d=10;//正确
x.a=10;//错误,发生冲突
return 0;
}
这段代码实现了上图所示的菱形继承,结果发生了错误,因为类 B 和类 C 中都有成员变量 a(从 A 类继承而来),编译器不知道选用哪一个,所以产生了歧义。
解决冲突问题有两种方法:
第一种方法,我们可以在 a 的前面指明它具体来自哪个类:
d.B::a=10; //正确
或
d.C::a=10;//正确
第二种方式:
为了解决多继承时的命名冲突和冗余数据问题,C++ 提出了虚继承,使得在派生类中只保留一份间接基类的成员。
声明虚基类的一般形式为
class 派生类名: 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 x;
x.b=10;//正确
x.c=10;//正确
x.d=10;//正确
x.a=10;//正确
return 0;
}
这段代码使用虚继承重新实现了上图所示的菱形继承,这样在派生类 D 中就只保留了一份成员变量 a,直接访问就不会再有歧义了。
虚继承的目的是让某个类做出声明,承诺愿意共享它的基类。其中,这个被共享的基类就称为虚基类(Virtual Base Class),本例中的 A 就是一个虚基类。在这种机制下,不论虚基类在继承体系中出现了多少次,在派生类中都只包含一份虚基类的成员。