现在的位置: 首页 > 综合 > 正文

虚继承与虚函数表

2013年12月08日 ⁄ 综合 ⁄ 共 2251字 ⁄ 字号 评论关闭

一 虚继承

1) 代码:

复制代码

Code
#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结尾,为什么?

复制代码

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
->= 10;

    pGD
->= 20;

    pGD
->= 30;

    pGD
->= 40;

    PrintMemberAndVT(pGD);

    delete pGD;

}

复制代码

 

6)验证代码结果:

 

7)总结:

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

 

二 虚继承运行时类型转化

 

1)代码验证:

 

复制代码

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


转自:http://www.cnblogs.com/itech/archive/2009/03/01/1399996.html

抱歉!评论已关闭.