在CPP中,是允许一个基类通过不同的途径重复继承同一个祖先类的。这时祖先类里面的成员就被拷贝多份,当外界想调用的时候编译器无法决定使用哪一个副本,因而会报错。
为了避免这种情况,CPP中产生了虚基类——Virtual base。
使用方法:在继承访问控制之前加上保留字:virtual
普通基类与虚基类之间的唯一区别只有在派生类重复继承了某一基类时才表现出来。
举个栗子:
class BASE {public: int i;};
class BASE1: virtual public BASE { //由于使用了virtual这里BASE变成了BASE1的一个虚基类。
public: int j;
};
class BASE2: virtual public BASE {
public: int k;
};
class DERIVED: public BASE1, public BASE2 {
public: int sum;
};
int main()
{
DERIVED obj; // 声明一个派生类对象
obj.i = 3; // 正确:从BASE继承的i在DERIVED中只有一份
obj.j = 5; // 正确:使用从BASE1继承的j
obj.k = 7; // 正确:使用从BASE2继承的k
return 0;
}
若派生类有一个虚基类作为祖先类,则在派生类构造函数中需要列出对虚基类构造函数的调用,即显示调用(否则,调用虚基类的默认构造函数),且对虚基类构造函数的调用总是先于普通基类的构造函数。
而普通基类的构造函数无需显示调用,只需在参数列表之后向其传递参数即可。
再结合之前的构造函数的调用顺序,感受一下下面这个例子:
#include "iostream"
using namespace std;
class baseA {
public:
baseA() {
cout << endl << "This is baseA class." << endl;
}
};
class baseB {
public:
baseB() {
cout << endl << "This is baseB class." << endl;
}
};
class derivedA : public baseB, virtual public baseA {
public:
derivedA() {
cout << endl << "This is derivedA class." << endl;
}
};
class derivedB : public baseB, virtual public baseA {
public:
derivedB() {
cout << endl << "This is derivedB class." << endl;
}
};
class Derived : public derivedA, virtual public derivedB {
public:
Derived() {
cout << endl << "This is Derived class." << endl;
}
};
int main() {
Derived obj;
return 0;
}
运行结果
This is baseA class.
This is baseB class.
This is derivedB class.
This is baseB class.
This is derivedA class.
This is Derived class.