C++对象模型探索.docx

  1. 1、本文档共8页,可阅读全部内容。
  2. 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
  3. 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载
  4. 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
第一章:继承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的命令行工具VisualStudio 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均可访问TestA,但两个指针指向的是不同的位置,在CDriver对CBaseB的虚函数表拷贝中,函数对应的项指向一个调整块的地址,该调整块进行必要运算,完成转换。thunk this-=12;多重继承中,发生派生类虚函数覆盖多个基类虚函数的

文档评论(0)

希望之星 + 关注
实名认证
内容提供者

我是一名原创力文库的爱好者!从事自由职业!

1亿VIP精品文档

相关文档