目录
前言
在上一篇的文章中我们知道了, C++语言是知识多继承的,并且一个子类可以有多个父类子类,拥有所有父类的成员变量,子类会继承父类的所有成员函数,而且子类的对象也可以被父类的任意对象使用
虚基类的作用
如果一个类中有多个直接的基类,并且这些直接的基类又有有一个共同的基类,则在最低层的派生类中就会保留这个间接的共同基类数据成员的多份同名成员,在我们下次访问,这些同名成员的时候,必须在派生类的对象名后直接增加基类名,并唯一的标识一个成员,这样会避免产生二义性
虚基类的声明
从之前的声明我们不难理解,如果类中只存在一个拷贝,(就是说如果只存在一个数据成员X)那么对X的访问就不会产生二义性,在C++中我们可以通过对这个公共的基类声明为虚基类来解决这个问题,这就会使用到我们接下来要讲解的关键字virtual ,virtual可以将一个类声明为虚基类
声明虚基类的语法形式如下:
class 派生类名:virtual 继承方式 类名{ ………… }
虚基类的初识化
虚基类的初始化与一般的多继承的初始化上的语法是一样的,但是要注意的一点是构造函数的调用顺序不同,在使用虚机类的机制时,应该注意以下的这几点 :
- 注意点一、如果在虚基类类的定义有带形参的构造函数,并且是没有定义默认形式的构造函数,那么在整个继承结构之中,所有间接或者直接引用的派生类,都必须在构造函数的成员初始化列表中指出对虚基类构造函数的调用,用来初始化,在虚基类中定义的数据成员。
- 注意点二、在我们建立一个新的对象的时候,如果这个对象中含有从虚基类中继承而来的成员,那么虚基类的成员是由最远的派生类的构造函数通过对该虚基类的构造函数进行调用来进行初始化的,该派生类中的其他基类对虚基类构造函数的调用都会被编译系统自动忽略
- 注意点三、对于同一程序中既包含虚基类也包含非虚基类,那么我们会自动调用虚基类中的构造函数,然后才调用非虚基类中的构造函数,最后是调用派生类的构造函数
- 注意点四、对于如果有多个虚基类构造,函数的执行顺序,仍然是按先左后右自上而下的顺序,但是对于非虚基类的构造,函数的执行顺序依然是先左后右,自上而下,若虚基类是由非虚基类派生而来的,那么我们仍然是先会调用基类中的构造函数,然后才调用派生类中的构造函数
最后我们就来看这个栗子:观察它是否运行正常,它的结果又是什么?
#include <iostream> using namespace std; class B : public A { public: B() { cout << 'is b'; } int b; }; class C : public A { public: C() { cout << 'is c'; } int c; }; class D : public B, public C { public: D() { cout << 'is d'; }; int d; }; int main() { D d; return 0; }