C++多继承与虚基类

来源:互联网 发布:淘宝卖家小号 编辑:程序博客网 时间:2024/06/05 03:08

》多继承中的二义性问题

        在派生类中对基类成员的访问应该是唯一的。但是,在多继承情况下,可能造成对基类中某个成员的访问出现了不唯一的情况,这时就称对基类成员的访问产生了二义性。

       示  例:

class base1{public:void fun();};class base2{public:void fun();};class derived:public base1,public base2{};int main(){derived obj;obj.fun();    //产生二义性         return 0;}
       当派生类derived的对象obj访问fun( )函数时,由于无法确定访问的是基类base1中的fun()函数,还是base2中的,因此对fun()函数的访问将产生二义性。

       解决这个问题的两种方法:

           (1)通过作用域运算符(::)明确指出访问的是基类base1的fun()函数,还是基类base2的fun()函数。

                         例:  obj.base1::fun();

                使用作用域运算符进行限定的一般格式:

                        <对象名>.<基类名>::<成员名>   //数据成员      <对象名>.<基类名>::<成员名>(<参数表>)   //成员函数

           (2)在类中定义同名成员。例:

class derived{public:void fun(){base1::fun();}  //注意两种表示方法的区别//或           base1::fun;   };
         在不同的作用域中声明标识符的可见性原则:如果存在两个或多个具有包含关系的作用域,如果在内层没有声明与外层声明标识符同名的标识符,那么它在内层可见;如果内层声明了同名标识符,则外层标识符在内层不可见,这时称内层变量覆盖了外层同名变量。

         在类的继承层次结构中,基类的成员和派生类新增的成员都具有类作用域,二者的作用范围不同,是相互包含的两个层,派生类在内层。这时,如果派生类定义了一个和某个基类成员同名的新成员(如果是成员函数,则参数表也要相同,参数不同的情况属于重载),派生的新成员就覆盖了外层同名成员,直接使用成员名只能访问到派生类的成员。

         产生二义性问题的另一种情况:当一个派生类从多个基类派生,而这些基类又有一个共同的基类,当对这个共同的基类中说明的成员进行访问时,可能出现二义性。由于二义性原因,一个类不能从同一个类中直接继承一次以上。

         由于二义性检查在访问控制权限或类型检查之前进行,因此访问控制权限不同或类型不同不能解决二义性问题。


》虚基类

        当一个派生类从多个基类派生,而这些基类又有一个共同的基类,当对该基类中说明的成员进行访问时,可能出现二义性。虚基类就是为了解决这种二义性问题提出来的。

        虚基类的说明格式:

                  class <类名>:virtual <继承方式> <基类名>

         其中,关键字virtual与继承方式的位置无关,但必须位于虚基类名之前,且virtual只对紧随其后的基类名有效。


》虚基类的构造函数

         为初始化基类子对象,派生类的构造函数要调用基类的构造函数。对于虚基类,由于派生类的对象中只有一个虚基类子对象,所以,在建立一个派生类的对象时,为保证虚基类子对象只被初始化一次,这个虚基类构造函数必须只被调用一次。虽然继承结构的层次可能很深,但要建立的对象所属的类只是这个继承结构中间的某个类,因此将在建立对象时所指定的类称为最派生类。

        虚基类子对象由最派生类的构造函数通过调用虚基类的构造函数实现。所以,最派生类的构造函数的初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的默认构造函数。

        由于最派生类总是相对的,因此,从虚基类直接或间接派生的派生类的构造函数的初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生类的构造函数才能调用虚基类的构造函数,此时最派生类的所有基类中列出的对虚基类的构造函数的调用在执行过程中都被忽略,从而保证对虚基类子对象只初始化一次。

        当在构造函数的初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数被调用。

0 0