虚继承与虚函数表

参考: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时地址的变化,第一个基类的地址与子类相同,其他的基类和虚基类需要做偏移。

 

posted @ 2012-07-15 18:19  Mr.Rico  阅读(...)  评论(...编辑  收藏