C++虚基类

对于直接继承,一个基类只能被派生类继承一次;

对于间接继承,一个基类可以被派生类继承多次。

如图所示的继承结构中,基类A在类D中会产生两个副本。这时如果在D类中使用从A类继承的成员时,如果不指定其作用域,会出现同名冲突。

   虚基类的基本思想是:将一个基类声明为虚基类时,不管它在派生类中被继承多少次,该基类中的成员在该派生类中始终只有一个副本,如图。

虚基类是通过关键字virtual实现的,定义虚基类的格式为:

class <派生类>:virtual <access><基类名>《,---,virtual<accesss<基类名>>》

{ ---  } ;

class<派生类名>:<access>virtual <基类名>《,---,<access>virtual<基类名>》

{---} ;

例1:使用虚基类,使派生类中只有基类一个副本。

# include <iostream.h>

class CFurniture

{ protected:

        int weight ;

public:

        CFurniture( ){ }

        void SetWeight (int i  ) { weight=i ;}

        int GetWeight ( ) {return weight ;}

};

{cout<<”sleeping ---\n’ ;}

class CBed:virtual public CFurniture   //A 定义虚基类

{public :

CBed ( ){ }

void sleep ( )

} ;

class CSofa:virtual public CFurniture   //B 定义虚基类

{ public:

CSofa ( ) { }

void WatchTV()

{cout<<”Watch TV . \n “ ;}

} ;

class CSleepSofa :public CBad ,public Csofa

{public :

  CSleepSofa ( ){  }

  void FoldOut ( )

{cout<<”Fold out the sofa 。 \n ” ;}

};

void main ()

{CSleepSofa ss ;

ss.SetWeight (20) ;            //C

cout<<ss.GetWeight( )<<’\n’ ;    //D

}

执行结果:

20

例 2    

#include <iostream.h>

class A {

public:

        int i;

        void showa(){cout<<"i="<<i<<endl;}

};

class B: virtual public A  //对类A进行了虚拟继承

{

public:

        int j;

};

                           

class C: virtual public A     //对类A进行了虚拟继承

{

public:

        int k;

}; 

class D : public B, public C

//派生类D的二基类B、C具有共同的基类A,但采用了虚拟继承

//从而使类D的对象中只包含着类A的1个实例

{

public:

        int n;

void showall(){cout<<"i,j,k,n="<<i<< “ ,”<<j<< “ ,”<<k<< “ ,”<<n<<endl;}

};

         

void main() {

        D Dobj;      //说明D类对象

        Dobj.i=11;

            //若非虚拟继承时会出错!

            // -- 因为“D::a”具有二义性

        Dobj.j=22;

    Dobj.k=33;

    Dobj.n =44;

        Dobj.showa();

            //若非虚拟继承时会出错!

            // -- 因为“D::showa”具有二义性

        Dobj.showall();

}

 

    程序执行后的显示结果如下:

/*

i=11

i,j,k,n=11 ,22 ,33 ,44

Press any key to continue

*/

虚基类的初始化

虚基类的初始化与一般的多重继承的初始化在语法上是一致的,但构造函数的调用次序有不同。

1.虚基类的构造函数在非虚基类的构造函数之前调用。如下例的B行

2.若同一层次中包含多个虚基类,这些虚基类的构造函数按它们的说明次序调用。

3.若虚基类由非虚基类派生而来,则仍然先调用基类的构造函数,再调用派生类的构造函数,如下例的A行。

4.对图的类层次结构,由于此时虚基类A在类D中只有一个副本,因此在创建D的对象时,无法确定是通过类B还是通过类C调用A的构造函数,为了解决这个矛盾,C++规定在这种情况下可以在类D中,直接调用类A的构造函数。

即在D类的构造函数的初始化成员列表中,不仅要调用类B和类C的构造函数,还必须调用类A的构造函数而且是最先调用。

因为在类D只有A的一个版本,所以调用类B和类C的构造函数时不再重复调用类A的构造函数了,即类A的构造函数只运行一次。

下面通过一个例子来说明这一个问题。

例3 虚基类的构造函数的调用次序

# include <iostream.h>

class CBase1

{public:

CBase1 ( ){cout<<”This is CBase1 class! \ n “ ;}

};

class CBase2

{public:

        CBase2 ( ) {cout<<”This is CBase2 class ! \n “ ;}

};

class CDerive1:public CBase2 ,virtual public CBase1   //A

{

public:

CDerive1( )

{cout<<”This is CDerive1 class ! \n “ ;}

};

class CDerive2:public CBase2 ,virtual public CBase1   //A

{

public:

CDerive2 ( )

{cout<<”This is CDerive2 class ! \n “ ;}

};

class CTop:public CDerive1 ,virtual public CDerive2   //B

{public:

CTop ( )

{cout<<”This is CTop class ! \n “ ;}

};

void main ( )

{ CTop topObj ; }

执行结果:

This is CBase1 class !

This is CBase2 class !

This is CDerive2 class !

This is CBase2 class !

This is CDerive1 class !

This is CTop class !

例4 初始化虚基类成员 

# include <iotream.h>

class CBase

{int  x  ,y ;

public:

CBase ( int a , int b )

{x=a , y=b ;}

show ( )

{cout<<x<<’\t’<<y<<endl ;}

};

class CDerive1:virtual public CBase           //A声明CBase为虚基类

{public:

CDerive1( ):CBase(2,3)

{  }

};

class CDerive2:virtual public CBase        //B声明CBase为虚基类

public:

CDerive2 ( ):CBase (4 ,5)

{    }

} ;

class CTop :public CDerive1,public CDerive2

{public:

 CTop ( ):CBase (6 , 7 )             //C直接调用虚基类CBase的构造函数,

{           }     //如果A、B行没有声明CBase为虚基类,则不可这样使用。

} ;

void main ( )

{CTop topObj ;

topObj.show() ;

}

执行结果;

6       7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值