虚基类、虚函数,对象内存分布

非虚拟继承:
 在派生类对象里,按照继承声明顺序依次分布基类对象,最后是派生类数据成员。
 若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
 在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
 派生类独有的虚函数被加在第一个基类的虚函数表后面。
 
 虚拟继承:
 在派生类对象里,按照继承声明顺序依次分布非虚基类对象,然后是派生类数据成员,最后是虚基类对象。
 若基类声明了虚函数,则基类对象头部有一个虚函数表指针,然后是基类数据成员。
 在基类虚函数表中,依次是基类的虚函数,若某个函数被派生类override,则替换为派生类的函数。
 若直接从虚基类派生的类没有非虚父类,且声明了新的虚函数,则该派生类有自己的虚函数表,在该派生类头部;否则派生类独有的虚函数被加在第一个非虚基类的虚函数表后面。
 直接从虚基类派生的类内部还有一个虚基类表指针,在数据成员之前,非虚基类对象之后(若有的话)。
 虚基类表中第一个值是该派生类起始地址到该表的偏移;之后的值依次是该派生类的虚基类到该表位置的地址偏移。

非虚拟单继承

 class  Base
   {
       virtual   void  Func2()  {cout << " Base " << endl;} 
      int  iBase;
 } ;
 
 class  Derived :  public  Base
   {
 public :
       void  Func2()  {cout << " Derived Func2 called " << endl;} ;
       void  Func3()  {cout << " Derived Func3 called " << endl;} ;
       virtual   void  Func5()  {cout << " Derived Func5 called " << endl;} ;
 
      int  iDerived;
 } ;

1>class Derived size(12):
1> +---
1> | +--- (base class Base)
1> 0 | | {vfptr}
1> 4 | | iBase
1> | +---
1> 8 | iDerived
1> +---
1>Derived::$vftable@:
1> | &Derived_meta
1> |  0
1> 0 | &Derived::Func2
1> 1 | &Derived::Func5

非虚拟多继承

 class  Base
   {
       virtual   void  Func2()  {cout << " Base " << endl;} 
      int  iBase;
 } ;
 
 class  Base1
   {
 public :
       virtual   void  Func1()  {cout << " Base1 Func1 called " << endl;} ;
       virtual   void  Func2()  {cout << " Base1 Func2 called " << endl;} ;
       virtual   void  Func3()  {cout << " Base1 Func3 called " << endl;} ;
      int  iBase1;
 } ;
 
 class  Base2
   {
 public :
       virtual   void  Func2()  {cout << " Base2 Func2 called " << endl;} ;
       virtual   void  Func3()  {cout << " Base2 Func3 called " << endl;} ;
       virtual   void  Func4()  {cout << " Base2 Func4 called " << endl;} ;
      int  iBase2;
 } ;
 
 class  Derived :  public  Base,  public  Base1,  public  Base2
   {
 public :
       void  Func2()  {cout << " Derived Func2 called " << endl;} ;
       void  Func3()  {cout << " Derived Func3 called " << endl;} ;
       virtual   void  Func5()  {cout << " Derived Func5 called " << endl;} ;
      int  iDerived;
 } ;

1>class Derived size(28):
1> +---
1> | +--- (base class Base)
1> 0 | | {vfptr}
1> 4 | | iBase
1> | +---
1> | +--- (base class Base1)
1> 8 | | {vfptr}
1>12 | | iBase1
1> | +---
1> | +--- (base class Base2)
1>16 | | {vfptr}
1>20 | | iBase2
1> | +---
1>24 | iDerived
1> +---
1>Derived::$vftable@Base@:
1> | &Derived_meta
1> |  0
1> 0 | &Derived::Func2
1> 1 | &Derived::Func5
1>Derived::$vftable@Base1@:
1> | -8
1> 0 | &Base1::Func1
1> 1 | &thunk: this-=8; goto Derived::Func2
1> 2 | &Derived::Func3
1>Derived::$vftable@Base2@:
1> | -16
1> 0 | &thunk: this-=16; goto Derived::Func2
1> 1 | &thunk: this-=8; goto Derived::Func3
1> 2 | &Base2::Func4

虚拟单继承

 class  Base
   {
 public :
       virtual   void  Func2()  {} ;
      int  BaseValue;
 } ;
 
 class  Derived :  virtual   public  Base
   {
 public :
       void  Func2()  {} ;
       virtual   void  Func4()  {} ;
      int  DerivedValue;
 } ;

1>class Derived size(20):
1> +---
1> 0 | {vfptr}
1> 4 | {vbptr}
1> 8 | DerivedValue
1> +---
1> +--- (virtual base Base)
1>12 | {vfptr}
1>16 | BaseValue
1> +---
1>Derived::$vftable@Derived@:
1> | &Derived_meta
1> |  0
1> 0 | &Derived::Func4
1>Derived::$vbtable@:
1> 0 | -4
1> 1 | 8 (Derivedd(Derived+4)Base)
1>Derived::$vftable@Base@:
1> | -12
1> 0 | &Derived::Func2

虚拟多继承

 class  Base
   {
       virtual   void  Func2()  {cout << " Base " << endl;} 
      int  iBase;
 } ;
 
 class  Base1
   {
 public :
       virtual   void  Func1()  {cout << " Base1 Func1 called " << endl;} ;
       virtual   void  Func2()  {cout << " Base1 Func2 called " << endl;} ;
       virtual   void  Func3()  {cout << " Base1 Func3 called " << endl;} ;
      int  iBase1;
 } ;
 
 class  Base2
   {
 public :
       virtual   void  Func2()  {cout << " Base2 Func2 called " << endl;} ;
       virtual   void  Func3()  {cout << " Base2 Func3 called " << endl;} ;
       virtual   void  Func4()  {cout << " Base2 Func4 called " << endl;} ;
      int  iBase2;
 } ;
 
 class  Derived :  public   virtual  Base,  public    virtual  Base1,  public   Base2
   {
 public :
       void  Func2()  {cout << " Derived Func2 called " << endl;} ;
       void  Func3()  {cout << " Derived Func3 called " << endl;} ;
       virtual   void  Func5()  {cout << " Derived Func5 called " << endl;} ;
      int  iDerived;
 } ;


1>class Derived size(32):
1> +---
1> | +--- (base class Base2)
1> 0 | | {vfptr}
1> 4 | | iBase2
1> | +---
1> 8 | {vbptr}
1>12 | iDerived
1> +---
1> +--- (virtual base Base)
1>16 | {vfptr}
1>20 | iBase
1> +---
1> +--- (virtual base Base1)
1>24 | {vfptr}
1>28 | iBase1
1> +---
1>Derived::$vftable@Base2@:
1> | &Derived_meta
1> |  0
1> 0 | &Derived::Func2
1> 1 | &Derived::Func3
1> 2 | &Base2::Func4
1> 3 | &Derived::Func5
1>Derived::$vbtable@:
1> 0 | -8
1> 1 | 8 (Derivedd(Derived+8)Base)
1> 2 | 16 (Derivedd(Derived+8)Base1)
1>Derived::$vftable@Base@:
1> | -16
1> 0 | &thunk: this-=16; goto Derived::Func2
1>Derived::$vftable@Base1@:
1> | -24
1> 0 | &Base1::Func1
1> 1 | &thunk: this-=24; goto Derived::Func2
1> 2 | &thunk: this-=24; goto Derived::Func3


菱形虚拟继承

 #include  < iostream > 
 
 using   namespace  std;
 class  Top
   {
 public :
       virtual   void  Func1()  {} ;
      int  TopValue;
 } ;
 
 class  Left:  virtual   public  Top
   {
 public :
       void  Func1()  {} ;
       virtual   void  Func2()  {} 
      int  LeftValue;
 } ;
 
 class  Right:  virtual   public  Top
   {
 public :
       void  Func1()  {} ;
      int  RightValue;
 } ;
 
 class  Derived :  public  Left,  public  Right
   {
 public :
       void  Func1()  {} ;
       void  Func3()  {} 
       virtual   void  Func4()  {} ;
      int  DerivedValue;
 } ;
 
 int  main()
   {
        
               Derived d;

               Derived* pd = &d;

               Top* pt = &d;

               cout<<( int *)pt<<endl;

               cout<<( int *)pd<<endl;


      return   0 ;
 }

1>class Derived size(32):
1> +---
1> | +--- (base class Left)
1> 0 | | {vfptr}
1> 4 | | {vbptr}
1> 8 | | LeftValue
1> | +---
1> | +--- (base class Right)
1>12 | | {vbptr}
1>16 | | RightValue
1> | +---
1>20 | DerivedValue
1> +---
1> +--- (virtual base Top)
1>24 | {vfptr}
1>28 | TopValue
1> +---
1>Derived::$vftable@Left@:
1> | &Derived_meta
1> |  0
1> 0 | &Left::Func2
1> 1 | &Derived::Func4
1>Derived::$vbtable@Left@:
1> 0 | -4
1> 1 | 20 (Derivedd(Left+4)Top)
1>Derived::$vbtable@Right@:
1> 0 | 0
1> 1 | 12 (Derivedd(Right+0)Top)
1>Derived::$vftable@Top@:
1> | -24
1> 0 | &Derived::Func1

如上代码的输出结果表示虚基类指针的地址比派生类指针地址多了24,符合上面列出的对象内存布局。

当通过对象访问基类成员时,无论是否为虚拟继承,都可以再编译时期获得对象内存布局,直接计算出偏移量访问。
当通过指针访问基类成员时,如果是非虚拟继承,直接计算偏移量访问;
如果是虚拟继承,需要先计算出虚基类表指针的偏移地址,再根据指针找到虚基类表,取虚基类表中该项的内容,根据此内容计算虚基类对象的偏移地址,再根据成员在虚基类对象中的偏移地址访问。 
所以一般说来,当从派生类中访问虚基类成员时,应该先强制转化派生类指针为虚基类指针,然后一直使用虚基类指针来访问虚基类成员变量。这样做,可以避免每次都要计算虚基类地址的开销。


虚函数表不一定在派生类对象的首地址,例如当派生类从基类虚拟继承时,派生类如果没有定义新的虚函数,那么在派生类的对象空间中,首先分布的是虚基类表,然后是派生类成员,最后是虚基类对象,虚函数表在虚基类对象开始位置。


 class  Base
   {
 public :
       virtual   void  fun()  {} 
 } ;
 
 class  Derived:  virtual   public  Base
   {
       void  fun()  {} 
      int  i;
 } ;

1>class Derived size(12):
1> +---
1> 0 | {vbptr}
1> 4 | i
1> +---
1> +--- (virtual base Base)
1> 8 | {vfptr}
1> +---
1>Derived::$vbtable@:
1> 0 | 0
1> 1 | 8 (Derivedd(Derived+0)Base)
1>Derived::$vftable@:
1> | -8
1> 0 | &Derived::fun

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值