虚基类

1.虚基类的概念
    
          在C++语言中,一个类不能被多次说明为一个派生类的直接基类,但可以不止一次地成为间接基类。这就导致了一些问题。为了方便 说明,先介绍多继承的“类格”表示法。
       
          派生类及其基类可用一有向无环图(DAG)表示,其中的箭头表示“由派生而来”。类的DAG常称为一个“类格”。复杂类格画出来通常更容易理解。例如:

5-19
class L
{ public:
int next;

};
class A : public L
{ };
class B : public L
{ };
class C : public A, public B
{ public :
void f()
{
next=0;
}
};


这时,next有两个赋值语句next=0; 具有二义性,它是将A::next置为零,还是将B::next置为零,或者将两者都置为0,需要在函数f()中被显式的说明.
如果希望间接基类L与其派生类的关系是如下图

 

当在多条继承路径上有一个公共的基类,在这些路径中的某几条路经汇合处,这个公共基类就会产生多个实例。

         如果只想保存这个基类的一个实例,可以将这个公共基类说明为虚拟基类或称虚基类。
         
       它仅是简单地将关键字virtual加到基类的描述上,例如改写上述例子为例5-20


注意!!!

 

一个派生类的对象的地址可以直接赋给虚基类的指针,例如:
             C  obj;
              L  * ptr=&obj;
    这时不需要强制类型转换,并且,一个虚基类的引用可以引用一个派生类的对象,例如:  
         C  obj2;
          L &ref=obj2;
       反之则不行,无论在强制类型转换中指定什么路径,一个虚基类的指针或引用不能转换为派生类的指针或引用。例如:
        C  * P=(C*)(A*)ptr;
 将产生编译错误。

 

 

2. 虚基类对象的初始化
        虚基类的初始化与多继承的初始化在语法上是一样的,但隐含的构造函数的调用次序有点差别。
        虚基类构造函数的调用次序是这样规定的:
        1. 虚基类的构造函数在非虚基类之前调用。
        2. 若同一层次中包含多个虚基类,虚基类构造函数按它们说明的次序调用。
        3. 若虚基类由非虚基类派生,则遵守先调用基类构造函数,再调用派生类构造函数的规则。

 

例如 :
           class  X :  public Y, virtual public Z
               {     }
                   X one;
         将产生如下调用次序:
                  Z()
                  Y()
                  X()
         这里Z是X的虚基类,故先调用Z的构造函数,再调用Y的构造函数,最后才调用派生类X自己的构造函数。



 

# include "iostream.h"       
class base
{
public:
base()
{cout<<"Base"<<endl;}
};
class base2
{
public:
base2()
{cout<<"Base2"<<endl;}
};

class level1 : public base2, virtual public base
{
public:
level1()
{cout<<"level1"<<endl;}
};
class level2 : public base2, virtual public base
{
public:
level2()
{cout<<"level2"<<endl;}
};
class toplevel : public level1, virtual public level2
{
public:
toplevel()
{cout<<"toplevel"<<endl;}
};

当建立对象view时,将产生如下调用次序:
            level2()
            level1()
            toplevel()
     而level2()要求:
       base()
        base2()
        level2()
        level1()要求
         base2()
         level1()
        toplevel()要求
         toplevel()

 

 

所以,构造函数的调用顺序为:
             base()
             base2()
             level2()        
          base2()
             level1()
             toplevel()


 

 

 

 

 

posted @ 2012-04-06 12:22  carbs  阅读(5372)  评论(0编辑  收藏  举报