虚基类的作用:消除二义性
前因:
1.C++中多重继承,即一个派生类可以有多个基类。如果多个基类有同名成员或同名函数,派生类对象对其访问时会产生二义性。
举例:
#include <iostream> using namespace std; class Base1 { public: Base1(int var){cout << "Base1" << endl; }; int var; void fun() { cout << "Base1::fun()" << endl; } }; class Base2 { public: Base2(int var){cout << "Base2" << endl;}; int var; void fun() { cout << "Base2::fun()" << endl; } }; class Derived : public Base1, public Base2 { public: Derived(int var) : Base1(var), Base2(var){cout << "Derived" << endl; }; //int var; //void fun() { cout << "Derived::fun()" << endl; } }; int main() { Derived d(1); d.var = 2; d.fun(); //cout<<"d.var = " <<d.var<<endl; return 0; }
输出:
2.如果多个基类又有一个共同的基类,则在最终的派生类中会保留多份同名的共同基类的数据成员。
避免二义性的访问方法: c.A::display( );
为了避免派生类中保留多份同名成员,C++提供了虚基类(virtual base class)的方法,在派生类中只保留一份成员。
声明:class 派生类名: virtual 继承方式 基类名
Class A //声明基类A
{...};
Class B1 : virtual public A //声明派生类B1,A是B1的虚基类
{...};
Class B2 : virtual public A //声明派生类B2,A是B2的虚基类
{...};
Class C : public B1, public B2 //声明派生类C,多继承B1和B2,只继承A一次
{...};
注意:
虚基类并不是在声明基类时声明的,而是在声明派生类时,指定继承方式时声明的。因为一个基类可以在生成一个派生类时作为虚基类,而在生成另一个派生类时不作为虚基类。
实例:
#include <iostream> using namespace std; class Base0 { public: Base0(int var) : var0(var) { cout << "Base0" << endl;}; int var0; void fun0() { cout << "Member of Base0" << endl; } }; class Base1 : virtual public Base0 { public: Base1(int var) : Base0(var){cout << "Base1" << endl; }; int var1; }; class Base2 : virtual public Base0 { public: Base2(int var) : Base0(var){cout << "Base2" << endl;}; int var2; }; class Derived : public Base1, public Base2 { public: Derived(int var) : Base0(var), Base1(var), Base2(var), var(0){cout << "Derived" << endl; }; int var; void fun() { cout << "Member of Derived" << endl; } }; int main() { Derived d(1); d.var0 = 2; d.fun0(); cout<<"d.var0 = " <<d.var0<<endl; cout<<"d.var1 = " <<d.var1<<endl; cout<<"d.var2 = " <<d.var2<<endl; cout<<"d.var = " <<d.var<<endl; return 0; }
输出:
注意:
1.在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用;
2.在建立对象时,只有最后派生类的构造函数调用虚基类的构造函数,而忽略虚基类的其他派生类,这样就保证了虚基类的数据成员不会被多次初始化。
参考来源:
https://www.cnblogs.com/yiranlaobaitu/p/3764422.html
https://blog.csdn.net/happyjacob/article/details/80781093
PS:
https://blog.csdn.net/qq_28114615/article/details/88077009 这篇博客介绍了虚继承的内存分布,非常详细