C++对象模型教程.docx

第一章:继承 1.1单一继承且无虚函数的对象模型 1.1.1实例: 1.1.2内存布局: ? 静态成员变量:被编译器提出对象之外,可视为全局变量并需在全局下定义,但生命周期依据类。 ? 静态成员函数没有this指针,故无法访问非静态成员函数和变量;无法用static和const修饰。 ? 非静态数据成员置于对象之内,静态数据成员置于对象之外。 ? 静态和非静态方法成员都被置于类对象之外。非静态成员的声明增加了两个属性:函数名标识的作用域;指向对象的this指针(隐含的第一个参数)。静态成员只是增加了函数名的作用域。 1.2单一继承且有虚函数的对象模型 1.2.1实例: 1.2.2内存布局: ? 只要类内有虚函数该,类的实例产生一个指向虚表格的指针。存在对象实例的顶部(VC\gcc)。 ? 这种线性继承的类对象只会维护一个虚表格,派生类的虚表格在基类虚表格的基础上做修改、增加。续表位于类定义模块。 ? 虚表格是一块连续的内存,每个内存存放的是一个JMP指令的地址。 ? 注意虚拟析构。 1.3多重继承、虚继承的对象模型 1.3.1多重继承: 多继承的虚表分布是否和线性单继承一样只维护一个续表?我们再次做出测试,测试的具体步骤省略,遍历发现程序报错。在此我们做出另外一种猜想,最终派生类维护的虚表数目和它继承的类数目有关?我们做出测试,测试的具体步骤如上图。成功遍历!!! 根据测试的结果可得出以下结论: ? 多继承的派生类维护的虚表数目等于它继承的类数目。 ? 派生它的内存分布: 内存排列:基类A的vptr指针、基类A的数据成员、基类B的vptr指针、基类B的数据成员…、派生类的数据成员。 1.3.2虚继承: 首先介绍一下微软VS提供的一个可以显示对象布局的工具: ? 启动VS2010的命令行工具Visual Studio 2010Command Prompt ? 切换到.cpp文件所在的路径,键入命令 cl [filename].cpp /d1reportSingleClassLayout[className] 依据测试结果我们能得出以下结论: ? 内存布局: ? 首先排列非虚继承的基类实例。 ? 存在虚继承时,派生类产生一个vbptr指针,但如果非虚继承基类存在vbptr指针则直接继承,与直接联系虚基类的偏移值添加到第一个vbptr内。 ? 排列派生类的新数据成员。 ? 在实例最后,排列每个虚基类的一个实例。 ? vbptr ? 对每个继承自虚基类的类实例,将增加一个隐藏的“虚基类表指针”(vbptr)成员变量,从而达到间接计算虚基类位置的目的。 ? 该变量指向一个全类共享的偏移量表,表中项目记录了对于该类而言,“虚基类表指针”与虚基类实例之间的偏移量。 ? 偏移值一般存放在第二项。 1.4继承中成员变量的开销 1.4.1没有继承: 没有任何继承关系时,访问成员变量和C语言的情况完全一样:从指向对象的指针,考虑一定的偏移量即可。 1.4.2单继承: 由于派生类实例与其基类实例之间的偏移量是常数0,所以可以直接利用基类指针和基类成员之间的偏移量关系,如此计算得以简化。 1.4.3多重继承: 虽然派生类与某个基类之间的偏移量可能不为0,然而,该偏移量总是一个常数。只要是个常数,访问成员变量,计算成员变量偏移时的计算就可以被简化。可见即使对于多重继承来说,访问成员变量开销仍然不大。 1.4.4虚继承: ? 当类有虚基类时,访问非虚基类的成员仍然是计算固定偏移量的问题。然而,访问虚基类的成员变量,开销就增大了,因为必须经过如下步骤才能获得成员变量的地址: ? 获取“虚基类表指针”; ? 获取虚基类表中某一表项的内容; ? 把内容中指出的偏移量加到“虚基类表指针”的地址上。 ? 如果不是通过指针访问,而是直接通过对象实例,则派生类的布局可以在编译期间静态获得,偏移量也可以在编译时计算,因此也就不必要根据虚基类表的表项来间接计算了。 ? 当声明了一个对象实例,用点“.”操作符访问虚基类成员c1时,由于编译时就完全知道对象的布局情况,所以可以直接计算偏移量。 1.5成员函数 X类每一个非静态的成员函数都会接受一个特殊的隐藏参数----this指针,类型为X* const。该指针在后台初始化为指向成员函数工作于其上的对象。同样,在成员函数体内,成员变量的访问是通过在后台计算与this指针的偏移来进行。 1.5.1覆盖成员函数: 覆盖是静态(根据成员函数的静态类型在编译时决定)还是动态(通过对象指针在运行时动态决定),依赖于成员函数是否被声明为“虚函数”。 1.5.2多重继承下虚函数: 参照1.3.1的多种继承的内存布局图,实例CBaseA和CDriver的起始地址相同,但CBaseB和CBaseC的起始地址却与它们不同。 pA和pB均可访问Te

您可能关注的文档

文档评论(0)

1亿VIP精品文档

相关文档