C++中的虚基类以及构造函数解析

来源:互联网 发布:使命召唤14知乎 编辑:程序博客网 时间:2024/06/06 01:20

当某类的部分或者全部直接基类是从另一个共同基类派生而来时,在这些直接基类中从上一级共同基类继承来的成员就拥有相同的名称。在派生类的对象中,这些同名数据成员在内存中同时拥有多个副本,同一个函数名会有多个映射。可以使用作用域分辨符来唯一标识并分别访问它们,也可以讲共同基类设置为需基类,这时从不同路径继承过来的同名函数成员在内存中就只有一份副本,同一个函数也只有一个映射。这样就解决了同名成员的唯一标识问题。

一、虚基类

先看下图:

代码:class Base0 {public:int var0;void fun();};class Base1 : public Base0 {public:int var1;};class Base2 : public Base0 {public:int var2;};class Derived : public Base2, public Base1 {public:int var;void fun();};

可知,Base1和Base2从Base0继承下来的var0和fun()在非virtual继承自Base0的情况下,var0和fun()在Derived中存在多个副本,使得Derived变得更加的臃肿。

则Derived类成员情况如图:

可以使用作用域分辨符来访问它们,如下:

Derived dr;dr.Base1::var0 = 2;dr.Base1::fun();

以下是虚基类继承方式:

代码:class Base0 {public:int var0;void fun();};class Base1 : virtual public Base0 {public:int var1;};class Base2 : virtual public Base0 {public:int var2;};class Derived : public Base2, public Base1 {public:int var;void fun();};

派生时Base0为虚基类,再以Base1、Base2作为虚基类的公有派生产生了新类Derived。这时的Derived类中,通过Base1和Base2两条路径继承下来的基类Base0中的var0和fun()只有一份副本。

则Derived类成员情况如图


二、虚继承后其派生类的构造函数

注意 : 如果虚基类声明又非默认形式的(即带参数的)构造函数,并且没有声明默认形式的构造函数,此时,在整个继承关系中,直接或者间接继承虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化。
代码:class Base0 {public:        Base(int var):var0(var){}int var0;void fun();};class Base1 : public Base0 {public:        Base1(int var):Base0(var){}int var1;};class Base2 : public Base0 {public:       Base2(int var):Base0(var){}int var2;};class Derived : public Base2, public Base1 {public:        Derived(int var):Base0(var),Base1(var),Base2(var){}int var;void fun();};
int main(){     Derived d(5);     d.var = 2;     d.fun();     return 0;}

建立Derived对象d时,直接调用了Base0、Base1、Base2的构造函数,但是并不会对Base0中的var0初始化三次!C++编译器对此种情况进行了处理,建立对象时,如果这个对象中含有从虚基类继承来的成员,则虚基类的成员由是由最远派生类(在这里是Derived类)的构造函数通过调用虚基类的构造函数进行初始化的,而该派生类的其他基类(即上例中的Base1和Base2)对虚基类构造函数的调用都自动被忽略。