1) 什么样本类会有虚表?
假设有一个类为ClassA,如果ClassA或者ClassA的父类中有虚函数,则ClassA就会有属于自己的虚表
2) 子类单继承一个父类,且无虚函数覆盖
子类会复制一份父类的虚表作为自己的虚表
3) 子类单继承一个父类,但有虚函数覆盖
子类会复制一份父类的虚表作为自己的虚表;
子类将需要覆盖的父类虚函数替换成自己的虚函数
4) 类的虚表可以有多个
假设ClassA继承了CBase1,CBase2且CBase1,CBase2都没有父类但都有虚函数,则ClassA将会有两张虚表,一张是从CBase1中拷贝过来的,一张是从CBase2中拷贝过来的
5) 子类新创建的虚函数放在该类的第一张虚表中的末尾
6) 类的虚函数表被该类的所有实例共享
7) 类对象的布局是按照类的继承顺序布局的
假设类的继承关系如下图所示:
图1
图1在加上第一段中的虚表继承规律可以知道:
CBase1,CBase2各有一张虚表;
ClassA,ClassB各有有两个虚表;
ClassA从CBase1中继承了一张表,从CBase2中继承了一张表,所以有两张表;
ClassB从ClassA中继承了两张表,因为ClassA有两张表
上述类对象的内存结构以及虚函数表在内存中的布局如下:
图2
我的代码在编译时取消了地址随机化,目的是为了方便测试。
class CBase1 { public: int m_nBase1; public: CBase1() { m_nBase1 = 1; } ~CBase1() {} virtual void Function1() { printf("CBase1::Function1"); } virtual void Function2() { printf("CBase1::Function2"); } }; class CBase2 { public: int m_nBase2; public: CBase2() { m_nBase2 = 2; } ~CBase2() {} virtual void Function3() { printf("CBase2::Function3"); } virtual void Function4() { printf("CBase2::Function4"); } }; class ClassA:public CBase1, public CBase2 { public: int m_nClassA; public: ClassA():CBase1(), CBase2(){ m_nClassA = 3; } ~ClassA() {} virtual void Function1() { printf("ClassA::Function1"); } virtual void Function3() { printf("ClassA::Function3"); } virtual void Function5() { printf("ClassA::Function5"); } }; class ClassB:public ClassA { public: int m_nClassB; public: ClassB():ClassA() { m_nClassB = 4; } ~ClassB() {} virtual void Function5() { printf("ClassB::Function5"); } virtual void Function6() { printf("ClassB::Function6"); } }; typedef void (*pFunction)(); int main() { CBase1 objCBase1; CBase2 objCBase2; ClassA objClassA; ClassB objClassB; DWORD* m_dwCBase1_table = (DWORD*) *(DWORD*)&objCBase1; DWORD* m_dwCBase2_table = (DWORD*) *(DWORD*)&objCBase2; DWORD* m_dwClassA_table1 = (DWORD*) *(DWORD*)&objClassA; DWORD* m_dwClassA_table2 = (DWORD*) *((DWORD*)&objClassA+2); DWORD* m_dwClassB_table1 = (DWORD*) *(DWORD*)&objClassB; DWORD* m_dwClassB_table2 = (DWORD*) *((DWORD*)&objClassB+2); printf("CBase1_VFT:\t0x%08x", m_dwCBase1_table); printf("\r\n\t\t0x%08x ", *(m_dwCBase1_table)); ((pFunction)*(m_dwCBase1_table))(); printf("\r\n\t\t0x%08x ",*(m_dwCBase1_table + 1)); ((pFunction)*(m_dwCBase1_table + 1))(); printf("\r\n"); printf("\r\nCBase2_VFT:\t0x%08x", m_dwCBase2_table); printf("\r\n\t\t0x%08x ", *(m_dwCBase2_table)); ((pFunction)*(m_dwCBase2_table))(); printf("\r\n\t\t0x%08x ", *(m_dwCBase2_table + 1)); ((pFunction)*(m_dwCBase2_table + 1))(); printf("\r\n"); printf("\r\nClassA_VFT1:\t0x%08x", m_dwClassA_table1); printf("\r\n\t\t0x%08x ", *(m_dwClassA_table1)); ((pFunction)*(m_dwClassA_table1))(); printf("\r\n\t\t0x%08x ", *(m_dwClassA_table1 + 1)); ((pFunction)*(m_dwClassA_table1 + 1))(); printf("\r\n\t\t0x%08x ", *(m_dwClassA_table1 + 2)); ((pFunction)*(m_dwClassA_table1 + 2))(); printf("\r\nClassA_VFT2:\t0x%08x", m_dwClassA_table2); printf("\r\n\t\t0x%08x ", *(m_dwClassA_table2)); ((pFunction)*(m_dwClassA_table2))(); printf("\r\n\t\t0x%08x ", *(m_dwClassA_table2 + 1)); ((pFunction)*(m_dwClassA_table2 + 1))(); printf("\r\n"); printf("\r\nClassB_VFT1:\t0x%08x", m_dwClassB_table1); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table1)); ((pFunction)*(m_dwClassB_table1))(); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table1 + 1)); ((pFunction)*(m_dwClassB_table1 + 1))(); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table1 + 2)); ((pFunction)*(m_dwClassB_table1 + 2))(); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table1 + 3)); ((pFunction)*(m_dwClassB_table1 + 3))(); printf("\r\nClassA_VFT2:\t0x%08x", m_dwClassB_table2); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table2)); ((pFunction)*(m_dwClassB_table2))(); printf("\r\n\t\t0x%08x ", *(m_dwClassB_table2 + 1)); ((pFunction)*(m_dwClassB_table2 + 1))(); printf("\r\n"); }
运行结果
图3
将图3结果整合到图2中得到图3,图3方便我们理解。
每个虚表的前面都会有一个 _s__RTTICompleteObjectLocator 类型的指针。通过分析该结构体就能获得该类的继承关系。
接下来需要了解几个重要结构体:
_s__RTTICompleteObjectLocator 位于虚表地址-4的地方 _TypeDescriptor 类型描述信息 _s__RTTIClassHierarchyDescriptor 类继承描述信息 _s__RTTIBaseClassArray 基类数组 _s__RTTIBaseClassDescriptor 基类描述信息 这里的 RTTI 是 RunTime Type Information 的缩写。
Step1:查看objCBase1变量信息得到虚表地址
0:000> dt objCBase1 Local var @ 0x19fed4 Type CBase1 +0x000 __VFN_table : 0x00419b34 //虚表地址 +0x004 m_nBase1 : 0n1
Step2:通过 __VFN_table - 4 查看虚表的 _s__RTTICompleteObjectLocator 结构体
0:000> dd 0x00419b30 L4 00419b30 0041aacc 00411253 0041121c 00000000 //0041aacc 为_s__RTTICompleteObjectLocator * //00411253 虚表的第一个元素,即CBase1::Function1() //0041121c 虚表的第二个元素,即CBase1::Function2() 0:000> dx -r1 ((_s__RTTICompleteObjectLocator *)0x0041aacc) ((_s__RTTICompleteObjectLocator *)0x0041aacc) : 0x41aacc [Type: _s__RTTICompleteObjectLocator *] [+0x000] signature : 0x0 [Type: unsigned long] [+0x004] offset : 0x0 [Type: unsigned long] [+0x008] cdOffset : 0x0 [Type: unsigned long] [+0x00c] pTypeDescriptor : 0x41c138 [Type: _TypeDescriptor *] [+0x010] pClassDescriptor : 0x41aae4 [Type: _s__RTTIClassHierarchyDescriptor *]
step3: 通过pTypeDescriptor查看类型描述信息
0:000> r @$t0=0x0041aacc //将_s__RTTICompleteObjectLocator的地址赋值给变量@$t0,方便后边引用 0:000> r @$t1=poi($t0+0x0c) //@$t1=pTypeDescriptor 0:000> dx -r1 ((_TypeDescriptor *)(@$t1)) ((_TypeDescriptor *)(@$t1)) : 0x41c138 [Type: _TypeDescriptor *] [+0x000] pVFTable : 0x419ecc [Type: void *] [+0x004] spare : 0x0 [Type: void *] [+0x008] name : ".?AVCBase1@@" [Type: char [0]] //该虚表属于CBase1
step4:通过pClassDescriptor查看类的继承描述信息
0:000> r @$t2=poi($t0+0x10);dx -r1 ((_s__RTTIClassHierarchyDescriptor *)(@$t2)) // @$t2是pClassDescriptor ((_s__RTTIClassHierarchyDescriptor *)(@$t1)) : 0x41aae4 [Type: _s__RTTIClassHierarchyDescriptor *] [+0x000] signature : 0x0 [Type: unsigned long] [+0x004] attributes : 0x0 [Type: unsigned long] [+0x008] numBaseClasses : 0x1 [Type: unsigned long] //几个基类 [+0x00c] pBaseClassArray : 0x41aaf8 [Type: _s__RTTIBaseClassArray *] //基类数组,每个元素的类型为_s__RTTIBaseClassDescriptor *
step5:通过 pBaseClassArray 获取基类信息
0:000> r @$t3 = poi($t2+0c);r $t3 $t3=0041aaf8 //$t3 = pBaseClassArray 0:000> r @$t4 = poi($t3);r $t4 $t4=0041ab00 //$t4 = pBaseClassArray[0] 0:000> dx -r1 ((_s__RTTIBaseClassDescriptor *)(@$t4)) ((_s__RTTIBaseClassDescriptor *)(@$t4)) : 0x41ab00 [Type: _s__RTTIBaseClassDescriptor *] [+0x000] pTypeDescriptor : 0x41c138 [Type: _TypeDescriptor *] [+0x004] numContainedBases : 0x0 [Type: unsigned long] //包含基类个数为0,表示只有自己一个类 [+0x008] where [Type: _PMD] [+0x014] attributes : 0x40 [Type: unsigned long] [+0x018] pClassDescriptor : 0x41aae4 [Type: _s__RTTIClassHierarchyDescriptor *] //该类的描述信息和step2中的一样
0:000> dt objClassA Local var @ 0x19fea8 Type ClassA +0x000 __VFN_table : 0x00419bb4 +0x004 m_nBase1 : 0n1 +0x008 __VFN_table : 0x00419bc8 +0x00c m_nBase2 : 0n2 +0x010 m_nClassA : 0n3 //虚表1的相关信息 0:000> dd 0x00419bb4-4 L8 00419bb0 0041ab7c 004111b3 0041121c 0041132f // 0041ab7c 是虚表1的描述信息结构体 00419bc0 00000000 0041ac00 004113f7 004110c8 //虚表2的相关信息 0:000> dd 0x00419bc8-4 L4 00419bc4 0041ac00 004113f7 004110c8 00000000 // 0041ac00 是虚表2的描述信息结构体 //虚表1的描述信息 0:000> dx -r1 ((_s__RTTICompleteObjectLocator *)0x0041ab7c) ((_s__RTTICompleteObjectLocator *)0x0041ab7c) : 0x41ab7c [Type: _s__RTTICompleteObjectLocator *] [+0x000] signature : 0x0 [Type: unsigned long] [+0x004] offset : 0x0 [Type: unsigned long] [+0x008] cdOffset : 0x0 [Type: unsigned long] [+0x00c] pTypeDescriptor : 0x41c170 [Type: _TypeDescriptor *] [+0x010] pClassDescriptor : 0x41ab94 [Type: _s__RTTIClassHierarchyDescriptor *] //查看虚表2的描述信息 0:000> dx -r1 ((_s__RTTICompleteObjectLocator *)0x0041ac00) ((_s__RTTICompleteObjectLocator *)0x0041ac00) : 0x41ac00 [Type: _s__RTTICompleteObjectLocator *] [+0x000] signature : 0x0 [Type: unsigned long] [+0x004] offset : 0x8 [Type: unsigned long] //虚表2在对象中的偏移量 [+0x008] cdOffset : 0x0 [Type: unsigned long] [+0x00c] pTypeDescriptor : 0x41c170 [Type: _TypeDescriptor *]//与虚表1中的pTypeDescriptor相同 [+0x010] pClassDescriptor : 0x41ab94 [Type: _s__RTTIClassHierarchyDescriptor *] //与虚表1中的pClassDescriptor相同 //查看虚表1,2属于哪个类 0:000> dx -r1 ((_TypeDescriptor *)0x41c170) ((_TypeDescriptor *)0x41c170) : 0x41c170 [Type: _TypeDescriptor *] [+0x000] pVFTable : 0x419ecc [Type: void *] [+0x004] spare : 0x0 [Type: void *] [+0x008] name : ".?AVClassA@@" [Type: char [0]] // 虚表1属于ClassA //查看类的继承信息 0:000> dx -r1 ((_s__RTTIClassHierarchyDescriptor *)0x41ab94) ((_s__RTTIClassHierarchyDescriptor *)0x41ab94) : 0x41ab94 [Type: _s__RTTIClassHierarchyDescriptor *] [+0x000] signature : 0x0 [Type: unsigned long] [+0x004] attributes : 0x1 [Type: unsigned long] [+0x008] numBaseClasses : 0x3 [Type: unsigned long] // 有3个基类 [+0x00c] pBaseClassArray : 0x41aba8 [Type: _s__RTTIBaseClassArray *] //基类数组 //查看3个基类的信息 0:000> dd 0x41aba8 L4 0041aba8 0041abb8 0041ab00 0041abdc 00000000 //基类1:0x0041abb8 0:000> dx -r1 ((_s__RTTIBaseClassDescriptor *)0x0041abb8) ((_s__RTTIBaseClassDescriptor *)0x0041abb8) : 0x41abb8 [Type: _s__RTTIBaseClassDescriptor *] [+0x000] pTypeDescriptor : 0x41c170 [Type: _TypeDescriptor *] [+0x004] numContainedBases : 0x2 [Type: unsigned long] //该类继承了2个基类 [+0x008] where [Type: _PMD] [+0x014] attributes : 0x40 [Type: unsigned long] [+0x018] pClassDescriptor : 0x41ab94 [Type: _s__RTTIClassHierarchyDescriptor *] 0:000> dx -r1 ((_TypeDescriptor *)0x41c170) ((_TypeDescriptor *)0x41c170) : 0x41c170 [Type: _TypeDescriptor *] [+0x000] pVFTable : 0x419ecc [Type: void *] [+0x004] spare : 0x0 [Type: void *] [+0x008] name : ".?AVClassA@@" [Type: char [0]] //0x0041abb8描述的类名是ClassA,且ClassA有两个父类。 //基类2:0x0041ab00 0:000> dx -r1 ((_s__RTTIBaseClassDescriptor *)0x0041ab00) ((_s__RTTIBaseClassDescriptor *)0x0041ab00) : 0x41ab00 [Type: _s__RTTIBaseClassDescriptor *] [+0x000] pTypeDescriptor : 0x41c138 [Type: _TypeDescriptor *] [+0x004] numContainedBases : 0x0 [Type: unsigned long] //该类没有父类 [+0x008] where [Type: _PMD] [+0x014] attributes : 0x40 [Type: unsigned long] [+0x018] pClassDescriptor : 0x41aae4 [Type: _s__RTTIClassHierarchyDescriptor *] 0:000> dx -r1 ((TestProjectC__!_TypeDescriptor *)0x41c138) ((TestProjectC__!_TypeDescriptor *)0x41c138) : 0x41c138 [Type: _TypeDescriptor *] [+0x000] pVFTable : 0x419ecc [Type: void *] [+0x004] spare : 0x0 [Type: void *] [+0x008] name : ".?AVCBase1@@" [Type: char [0]] //0x0041ab00描述的类名为CBase1,且CBase1没有父类 //基类3:0x0041abdc 0:000> dx -r1 ((_s__RTTIBaseClassDescriptor *)0x0041abdc) ((_s__RTTIBaseClassDescriptor *)0x0041abdc) : 0x41abdc [Type: _s__RTTIBaseClassDescriptor *] [+0x000] pTypeDescriptor : 0x41c154 [Type: _TypeDescriptor *] [+0x004] numContainedBases : 0x0 [Type: unsigned long] //该类没有父类 [+0x008] where [Type: _PMD] [+0x014] attributes : 0x40 [Type: unsigned long] [+0x018] pClassDescriptor : 0x41ab3c [Type: _s__RTTIClassHierarchyDescriptor *] 0:000> dx -r1 ((_TypeDescriptor *)0x41c154) ((_TypeDescriptor *)0x41c154) : 0x41c154 [Type: _TypeDescriptor *] [+0x000] pVFTable : 0x419ecc [Type: void *] [+0x004] spare : 0x0 [Type: void *] [+0x008] name : ".?AVCBase2@@" [Type: char [0]] //0x0041abdc描述的类名为CBase2,且CBase2没有父类 0:000> dx -r1 (*((_PMD *)0x41abe4)) (*((_PMD *)0x41abe4)) [Type: _PMD] [+0x000] mdisp : 8 [Type: int] //该类的成员数据在子类对象中的偏移量 [+0x004] pdisp : -1 [Type: int] [+0x008] vdisp : 0 [Type: int]
整理了一下这几个结构体的关系图,图4.
图4
自己可以试着手动分析objClassB.
有时间再画一下剩下的两个关系图。
返回