o的指针,如果这时候创建一个CVirtualNull对象,会发现它的虚表的内容跟这个一样
评注:由于父类带了虚函数,子类就算没有显式声明虚函数,虚表还是存在的,虚表存放的位置跟父类不同,但内容是同的,也就是对父类虚表的复制。
十三、子类有新的虚函数
C++代码
classCVirtualDerived:publicCVirtualNull
{
public:
CVirtualDerived(){m_iVD=0xFF;};
~CVirtualDerived(){};
virtualvoidFoo2(){printf("Foo2/n");};
private:
intm_iVD;
};
长度:8
内存结构:
24 61 42 00 //虚表指针
FF 00 00 00 //m_iVD
00426124:(虚表)
23 10 40 00
50 10 40 00
评注:虚表还是只有一张,不会因为增加了新的虚函数而多出另一张来,新的虚函数的指针将添加在复制了的虚表的后面。
十四、当纯虚函数(pure function)出现时
C++代码
classCPureVirtual
{
virtualvoidFoo()=0;
};
classCDerivePV:publicCPureVirtual
{
voidFoo(){printf("vd:Foo/n");};
};
长度:4(CPureVirtual),4(CDerivePV)
内存结构:
CPureVirtual:
(不可实例化)
CDerivePV:
28 50 42 00 //虚表指针
00425028:(虚表)
5A 10 40 00 //指向Foo的函数指针
评注:带纯虚函数的类不可实例化,因此列不出其“内存结构”,由其派生类实现纯虚函数。我们可以看到CDerivePV虽然没有virtual声明,但由于其父类带virtual,所以还是继承了虚表,如果CDerivePV有子类,还是这个道理。
十五、虚函数类的多重继承
前面提到:(子类的虚表)不会因为增加了新的虚函数而多出另一张来,但如果有多重继承的话情况就不是这样了。下例中你将看到两张虚表。
大小:24
内存结构
F8 50 42 00 //虚表指针
01 00 00 00 //m_iA
02 00 00 00 //m_iB
E8 50 42 00 //虚表指针
03 00 00 00 //m_iC
04 00 00 00 //m_iComplex
004250F8:(虚表)
5A 10 40 00 //FooA
55 10 40 00 //FooB
64 10 40 00 //FooComplex
004250E8:(虚表)
5F 10 40 00 //FooC
评注:子类的虚函数接在第一个基类的虚函数表的后面,所以B接在A后面,Complex接在B后面。基类依次出现,子类成员接在最后面,所以m_iComplex位于最后面。
十六、包含虚函数类的虚继承
C++代码
classVirtualInheritance
{
chark[3];
public:
virtualvoidaa(){};
};
classsonClass1:publicvirtualVirtualInheritance
{
charj[3];
public:
virtualvoidbb(){};
};
classsonClass2:publicvirtualsonClass1
{
charf[3];
public:
virtualvoidcc(){};
};
intmain()
{
cout
return0;
}
输出的结果:
visio studio: 8,20,32
gcc: 8,16,24
评注:
对于VirtualInheritance类,大小为8, 没有异议,他有个虚表指针vtp_VirtualInheritanc;
对于sonClass1类:
在visio studio 编译器下,大小为20。由于是虚拟继承,又有自己的虚函数,所以先拥有一个自己的虚函数指针vpt_sonClass1,大小为4,指向自己的虚表;还要有一个char[3],大小为4;为了实现虚拟继承,首先sonClass1加入了一个指向其父类的虚类指针,记作vtp_sonClass1_VirtualInheritanc,大小为4;然后在加上父类的所有大小8,所以总共是20字节。
在gcc编译器下,大小为16,没有计算子类中指向父类的虚类指针vtp_sonClass1_VirtualInheritanc的大小。
对于sonClass2:
在visio studio环境下,大小为32。和上面一样,子类拥有char[3],大小为4字节,因为是虚继承,还有自己的虚函数,所以拥有自己的一个虚表指针,vtp_sonClass2,大小为4字节。然后还有一个指向父类的虚类指针vtp_sonClass2_sonClass
1,大小为4。最后加上其父类的总大小20,所以总的大小为4+4+4+20=32;
在gcc环境下,没有计算虚类指针的大小,即4+4+16=24。
17、包含虚函数的多重普通、虚拟混合继承
C++代码
classVirtualInheritance
{
chark[3];
public:
virtualvoidaa(){};
};
classsonClass1:publicvirtualVirtualInheritance
{
charj[3];
public:
virtualvoidbb(){};
};
classVirtualInheritance2
{
charl[3];
public:
virtualvoiddd(){};
};
classsonClass2:publicvirtualsonClass1,publicVirtualInheritance2
{
charf[3];
public:
virtualvoidcc(){};
};
intmain()
{
cout
return0;
}
评注:此时sonClass2的大小变成36。和16不同的是,此时sonClass2是多重继承,其中一个是虚继承,一个普通继承,他的大小在visio studio中变成36,相比16增加了4,这刚好是char l[3]的大小,因为耸sonClass2已经有了一个虚表,所以在他原有的虚表中多一条记录即可。
18、包含虚函数的多重虚拟继承
C++代码
classVirtualInheritance
{
chark[3];
public:
virtualvoidaa(){};
};
classsonClass1:publicvirtualVirtualInheritance
{
charj[3];
public:
virtualvoidbb(){};
};
classVirtualInheritance2
{
charl[3];
public:
virtualvoiddd(){};
};
classsonClass2:publicvirtualsonClass1,publicvirtualVirtualInheritance2
{
charf[3];
public:
virtualvoidcc(){};
};
intmain()
{
cout
return0;