下午闲来没事,在2005下面探究了一下C++的虚表模型。总结如下:
1. 对相同的同一个class 创建多个object,可以发现 vfptr是指向同一个地址,
可见一个class 维护一个虚表,与创建对象没有关系
2. 如果一个基类(没有通过继承创建)含有virtual 函数,则这个这个类会
额外产生一个虚表,其大小是其成员变量,加上一个函数指针的大小。
3. 虚表的作用用来实现多态, 其最终的原理是基类可以透明的通过vfptr[index]
来访问成员函数,这就意味着同一个继承里面的class群,其vfptr每个index
对应的函数是相同的。
4. vfptr的开始的地址用来存放函数指针,后面部分用来存放RTTI信息
5. 派生类的构造过程:
1.构造基类,此时this 指针指向的vfptr是基类的vfptr
2.构造派生类,vfptr的地址转移到派生类的vfptr
这意味着,在构造函数期间,无法实现本Class体系的多态的行为
6. 析构的过程和构造一样,会存在vfptr转换的情况
7. 基类的析构函数如果不是virtual 的会导致基类无法析构
此外还有更严重的问题:
如果基类没有虚函数,其则不会产vfptr,此时如果派生有虚函数,
则派生类会产生vfptr,这样会导致赋值异常.
Derive* pDerive = new Derive();
Base *pTestBase = pDerive;
例如本例中,最终pTestBase 和 pDerive是不等的
pDerive = 0x003A4F58
pTestBase = 0x003A4F5C
其内存镜像为
0x003A4F58 40 67 41 00
0x003A4F5C 01 00 00 00
0x003A4F60 02 00 00 00
0x003A4F64 03 00 00 00
pDerive 的tihs 指针指向虚表
而pTestBase没有虚表,会指向第一个元素
#include <cstdio>
#include <iostream>
#define TRACE() printf("%s/r/n",__FUNCTION__);
class Base
{
public:
Base()
{
TRACE();
m_1 = 1;
m_2 = 2;
m_3 = 3;
}
/*virtual*/ ~Base()
{
TRACE();
}
//virtual void Fun1()
//{
// TRACE();
//}
//virtual void Fun2()
//{
// TRACE();
//}
//virtual void Fun3()
//{
// TRACE();
//}
private:
int m_1;
int m_2;
int m_3;
};
class Derive :public Base
{
public:
Derive()
{
TRACE();
};
/*virtual*/ ~Derive()
{
TRACE();
};
void virtual Testfun()
{
}
};
int main()
{
//Base* pDerive = new Derive();
Derive* pDerive = new Derive();
Base *pTestBase = pDerive;
printf("This : 0x%08x vptr :0x%08x/r/n",pDerive,((int *)pDerive)[0]);
printf("This : 0x%08x vptr :0x%08x/r/n",pTestBase,((int *)pTestBase)[0]);
delete pTestBase;
}