[C++对象模型][9]虚继承与虚函数表
一 虚继承
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;}
};
#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->i = 10;
pGD->x = 20;
pGD->y = 30;
pGD->a = 40;
PrintMemberAndVT(pGD);
delete pGD;
}
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)代码验证:
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;
}
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时地址的变化,第一个基类的地址与子类相同,其他的基类和虚基类需要做偏移。
三 完!