概述
当在多条继承路径上有一个公共的基类,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明为虚基类.
- classx1:virtual public x
- {
- //……
- };
- classx2:virtual public x
- {
- //……
- };
虚基类的初始化
虚基类的初始化与一般多继承的初始化在语法上是一样的,但构造函数的调用次序不同.
派生类构造函数的调用次序有三个原则:
(1)虚基类的构造函数在非虚基类之前调用;
(2)若同一层次中包含多个虚基类,这些虚基类的构造函数按它们说明的次序调用;
(3)若虚基类由非虚基类派生而来,则仍先调用基类构造函数,再调用派生类的构造函数.
C++的虚基类
在派生类继承基类时,加上一个virtual关键词则为虚拟基类继承,如:
- classderive:virtual public base
- {
- };
虚基类主要解决在多重继承时,基类可能被多次继承,虚基类主要提供一个基类给派生类,如:
- classB
- {
- };
- classD1:public B
- {
- };
- classD2:public B
- {
- };
- classC:public D1,public D2
- {
- };
这里C在D1,D2上继承,但有两个基类,造成混乱。因而使用虚基类,即:
- classB
- {
- };
- classD1:virtual public B
- {
- };
- classD2:virtualpublicB
- {
- };
- classC:public D1,public D2
在使用虚基类时要注意
(1) 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。
(2) 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。
(3) 虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化的。
(4) 最派生类是指在继承结构中建立对象时所指定的类。
(5) 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。
(6) 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象只初始化一次。
(7) 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行。
虚基类在继承中的优先性
遵循两个原则,而且按顺序优先满足:1 先调用完所以基类,再调用子类;2 先调用虚拟基类,再调用非虚拟基类。
- //base1
- #ifndef BASE1_H
- #define BASE1_H
- #include <iostream>
- using std::cout;
- using std::endl;
- class base1
- {
- public:
- base1()
- {
- cout << "base1" << endl;
- }
- };
- #endif
- //base2
- #ifndef BASE2_H
- #define BASE2_H
- #include <iostream>
- using std::cout;
- using std::endl;
- class base2
- {
- public:
- base2()
- {
- cout << "base2" << endl;
- }
- };
- #endif
- //sub1
- #ifndef SUB1_H
- #define SUB1_H
- #include <iostream>
- using std::cout;
- using std::endl;
- #include "base1.h"
- #include "base2.h"
- class sub1 : public base1,public base2
- {
- public:
- sub1()
- {
- cout << "sub1" << endl;
- }
- };
- #endif
- //sub2
- #ifndef SUB2_H
- #define SUB2_H
- #include <iostream>
- using std::cout;
- using std::endl;
- #include "base1.h"
- #include "base2.h"
- class sub2 : public base2,public base1
- {
- public:
- sub2()
- {
- cout << "sub2" << endl;
- }
- };
- #endif
- //test
- #ifndef TEST_H
- #define TEST_H
- #include <iostream>
- using std::cout;
- using std::endl;
- #include "sub1.h"
- #include "sub2.h"
- class test1 : public sub1,virtual public sub2
- {
- public:
- test1()
- {
- cout << "test1" << endl;
- }
- };
- class test2 : public sub2,public sub1
- {
- public:
- test2()
- {
- cout << "test1" << endl;
- }
- };
- #endif
- //main
- #include <iostream>
- using std::cin;
- #include "test.h"
- int main()
- {
- int i;
- test1 a;
- cin >> i ;
- }
- //输出:
- base2 base1 sub2 base1 base2 sub1 test1