由于C++中允许多继承,所以会出现二义性问题:在多个派生类中,定义了相同名字的方法,这时再在main函数里面通过基类调用该方法时,编译器就犯难了。因为它不知道你到底是想用哪一个派生类里面的方法。
那么,现在又有了一个问题:假如有两个派生类DerivedA和DerivedB,它们的同名方法一个有参数,一个没有参数,是不是不会出现二义性问题了?
或者说,这两个派生类方法的一个是private,一个是public,是不是就可以防止二义性了呢?
答案是否定的。二义性的检查应在访问控制权限或者类型检查之前进行,因此访问控制权限不同或类型不同不能解决二义性问题。
既然上述提出的假设成立,那么应该怎样去有效的解决二义性问题呢?
虚基类就是为了这个解决这种二义性问题提出来的。
二义性产生的最主要原因是:基类在派生类中产生了两个子对象,从而导致了对基类成员访问的不唯一性。所以只需要使公共基类只产生一个子对象,就可以了。
也就是说,保证虚基类构造函数只被调用一次即可。虚基类自对象是由最派生类的构造函数通过调用虚基类的构造函数实现,此时,最派生类的所有基类中列出的对虚基类的构造函数的调用在执行过程中都将被忽略,而从保证对虚基类自对象值初始化一次。同时,最派生类的初始化列表必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的默认构造函数。
(在继承结构的层次中,建立的对象属于这个结构中间的某个类,建立对象时所制定的类就是最派生类)
下面通过一个小例子分析一下:
#include <iostream> using namespace std; //基类 class Base { //公有成员 public: Base(char i) { cout << "Base's cons." << i<< endl; } ~Base() { cout << "Base's des." << endl; } }; //派生类1 class Derivedl1:virtual public Base { //公有成员 public: Derivedl1(char i,char j):Base(i) { cout << "Derivedl1's cons." << j<< endl; } ~Derivedl1() { cout << "Derived's des." << endl; } //私有成员 private: char b; }; //派生类2 class Derivedl2:virtual public Base { //公有成员 public: Derivedl2(char i,char j):Base(i) { cout << "Derivedl2' cons." << j <<endl; } ~Derivedl2() { cout << "Derived12' des." << endl; } }; //继承基类Base的派生类 class Derived2: public Derivedl1,public Derivedl2 { //公有成员 public : Derived2(char i,char j,char k,char l,char m,char n) :Derivedl2(k,l),Derivedl1(i,j),Base(i),aa(m) { cout << "Derived2's cons." <<n << endl; } ~Derived2() { cout << "Derived2's des." << endl; } //私有成员 private : Base aa; }; //main函数 int main() { Derived2 obj('a','b','c','d','e','f'); return 0; }
Main()中定义Derived2类对象obj,要调用它的构造方法。由于该类存在一个成员对象aa,且根据C++的规定,Derived类先调用虚基类Base,然后再调用两个直接基类Derivedl1和Derivedl2;然后在调用成员对象的构造函数初始化成员对象aa;最后再执行派生类Derived2的构造函数。
直接基类的执行顺序取决于定义派生类时声明基类的顺序,而与派生类构造函数的初始化列表顺序无关,所以先执行Derivedl1,后执行Derivedl2。
类Derivedl1也是一个派生类,它继承Base虚基类。而由于它的示例已经存在于最派生类Derived2,所以后面的调用不会再执行。
同时析构函数的执行顺序与构造函数严格相反。所以,该程序的执行解决是:
本文主要介绍了解决C++中二义性问题一种方案——虚基类。路过的童鞋希望留下宝贵意见。