虚继承与虚函数表

参考:http://www.cnblogs.com/itech/archive/2009/02/27/1399996.html

一 虚继承

1) 代码:

 #include <iostream>
  using  namespace std;
  class B
 {
  public:
      int i;
      virtual  void vB(){ cout <<  " B::vB " << endl; }
      void fB(){ cout <<  " B::fB " << endl;}
 };
  class D1 :  virtual  public B
 {
  public:
      int x;
      virtual  void vD1(){ cout <<  " D1::vD1 " << endl; }
      void fD1(){ cout <<  " D1::fD1 " << endl;}
 };
  class D2 :  virtual  public B
 {
  public:
      int y;
      void vB(){ cout <<  " D2::vB " << endl;}
      virtual  void vD2(){ cout <<  " D2::vD2 " << endl;}
      void fD2(){ cout <<  " D2::fD2 " << endl;}
 };
  class GD :   public D1,  public D2
 {
  public:
      int a;
      void vB(){ cout <<  " GD::vB " << endl;}
      void vD1(){cout <<  " GD::vD1 " << endl;}
      virtual  void vGD(){cout <<  " GD::vGD " << endl;}
      void fGD(){cout <<  " GD::fGD " << endl;}
 };                                                                              

 

2)类图:

 

 3)VS2008的编译选项查看布局:

 

 4)可视化表示:

5)代码验证:( 此时的虚函数表不是以NULL结尾,为什么?
View Code
typedef  void (*Fun)();

void PrintMember( int *pI)
{
    cout << *pI << endl << endl;
}
void PrintVT( int *pVT)
{
     while(*pVT != NULL)
    {
        (*(Fun*)(pVT))();
        pVT++;
    }
}

void PrintMemberAndVT(GD *pGD)
{
     int *pRoot = ( int*)pGD;

     int *pD1VT = ( int*)*(pRoot +  0); 
    (*(Fun*)(pD1VT))(); (*(Fun*)(pD1VT + 1))();
     int *pVB = ( int*)*(pRoot + 1);  cout <<  " vbtable's adress: " << *pVB << endl;
     int *pX = (pRoot +  2); PrintMember(pX);

     int *pD2VT = ( int*)*(pRoot +  3); 
    (*(Fun*)(pD2VT))();
     int *pVB2 = ( int*)*(pRoot + 4); cout <<  " vbtable's adress: " << *pVB2 << endl;
     int *pY = (pRoot +  5); PrintMember(pY);

     int *pA = (pRoot +  6); PrintMember(pA);

     int *pBVT = ( int*)*(pRoot +  7); 
    (*(Fun*)(pBVT))();
     int *pI = (pRoot +  8); PrintMember(pI);
}

void TestVT()
{
    B *pB =  new GD();
    GD *pGD = dynamic_cast<GD*>(pB);
    pGD->i =  10;
    pGD->x =  20;
    pGD->y =  30;
    pGD->a =  40;
    PrintMemberAndVT(pGD);
    delete pGD;
}

6)验证代码结果:

7)总结:

虚继承,使公共的基类在子类中只有一份,我们看到虚继承在多重继承的基础上多了vbtable来存储到公共基类的偏移。

 

二 虚继承运行时类型转化

 

1)代码验证:

void TestDynamicCast()
{
    B *pB =  new GD();
    GD *pGD = dynamic_cast<GD*>(pB);
    cout <<  " GD: " << pGD << endl;
    D1 *pD1 = dynamic_cast<D1*>(pB);
    cout <<  " D1: " << pD1 << endl;
    D2 *pD2 = dynamic_cast<D2*>(pB);
    cout <<  " D2: " << pD2 << endl;
    cout <<  " B: " << pB << endl;
}

 

2)验证代码结果:

 

3)总结:

还是从内存布局来看dynamic_cast时地址的变化,第一个基类的地址与子类相同,其他的基类和虚基类需要做偏移。

 

你可能感兴趣的:(虚函数)