已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
动态联编实现原理分析所谓动态联编,是指被调函数入口地址是在运行时、而不是在编译时决定的。C+语言利用动态联编来完成虚函数调用。C+标准并没有规定如何实现动态联编,但大多数的C+编译器都是通过虚指针(vptr)和虚函数表(vtable)来实现动态联编。基本的思路是:(1)为每一个包含虚函数的类建立一个虚函数表,虚函数表的每一个表项存放的是个虚函数在内存中的入口地址;(2)在该类的每个对象中设置一个指向虚函数表的指针,在调用虚函数时,先采用虚指针找到虚函数表,确定虚函数的入口地址在表中的位置,获取入口地址完成调用。我们将从以下几个方面来考察动态联编的实现细节。1.虚指针(vptr)的存放位置虚指针是作为对象的一部分存放在对象的空间中。一个类只有一个虚函数表,因此类的所有对象中的虚指针都指向同一个地方。在不同的编译器中,虚指针在对象中的位置时不同的。两种典型的做法是:(1)在Visual C+中,虚指针位于对象的起始位置;(2)在GNU C+中,虚指针位于对象的尾部而不是头部。可通过下面的程序考察在Visual C+中,虚指针在对象中的位置。#include using namespace std;int globalv;class NoVirtualint i;public:void func()coutno virtual functionendl;NoVirtual()i=+globalv;class HaveVirtual:public NoVirtualpublic:virtual void func()coutVirtual Functionendl;int main()NoVirtual n1, n2;HaveVirtual h1, h2;unsigned long* p;coutsizeof(NoVirtual):sizeof(NoVirtual)endl;coutsizeof(HaveVirtual):sizeof(HaveVirtual)endl;p=reinterpret_cast(&n1);coutfirst 4 bytes of n1:p0endl;p=reinterpret_cast(&n2);coutfirst 4 bytes of n2:p0endl;p=reinterpret_cast(&h1);coutfirst 4 bytes of h1: 0xhexp0endl;p=reinterpret_cast(&h2);coutfirst 4 bytes of h2: 0xhexp0endl;程序运行结果:从程序的输出结果中,可以得出以下两个结论。(1)可以清楚地的看到虚指针对类对象大小的影响。类NoVirtual不包含虚函数,因此类NoVirtual的对象中只包含数据成员i,所以sizeof(NoVirtual)为4。类HaveVirtual包含虚函数,因此类HaveVirtual的对象不近要包含数据成员i,还要包含一个指向虚函数表的指针(大小为4B),所以sizeof(HaveVirtual)为8。(2)虚指针如果不在对象的头部,那么对象h1和对象h2的头4个字节(代表整型成员变量i)的值应该是3和4。而程序结果显示,类HaveVirtual的两个对象h1和h2的头4个字节的内容相同,这个值就是类HaveVirtual的虚函数表所在地址。2.虚函数表(vtable)的内部结构虚函数表是为拥有虚函数的类准备的。虚函数表中存放的是类的各个虚函数的入口地址。那么,可以思考以下几个问题:(1)虚函数的入口地址是按照什么顺序存放在虚函数表中的呢?(2)不同的类(比如说父类和子类)是否可以共享同一张虚函数表的呢?(3)虚函数表是一个类的对象共享,还是一个对象就拥有一个虚函数表?(4)多重继承的情况下,派生类有多少个虚函数表呢?考察如下程序:#include using namespace std;#define ShowFuncAddress(function) _asmmov eax, function_asmmov p,eaxcoutAddress of #function: pendl;void showVtableContent(char* className, void* pObj, int index)unsigned long* pAddr=NULL;pAddr=reinterpret_cast(pObj);pAddr=(unsigned long*)*pAddr; /获取虚函数表指针coutclassNames vtableindex;cout: 0x(void*)pAddrindexendl;class Baseint i;public:virtual void f1()coutBases f1()endl;virtual void f2()coutBases f2()endl;virtual void f3()coutBases f3()endl;class Derived:public Baseint i;public:virtual void f4()coutDeriveds f4()endl;void f3()coutDeriveds f3()endl;void f1()coutDeriveds f1()endl;void func()coutlalaendl;int main()Base b;Derived d;void *p;unsigned long *pAddr;pAddr=reinterpret_cast(&b);coutaddress of vtable of Base is Ox(void*)*pAddrendl;pAddr=reinterpret_cast(&d);coutaddress of vtable of Derived is Ox(void*)*pAddrf();/Derive:f()b2-f();/Derive:f()b3-f();/Derive:f()b1-g();/Base1:g()b2-g();/Base2:g()b3-g();/Base3:g()3.虚函数表(vtable)的放在哪里虚函数表放在应用程序的常量区。将上面的代码编译之后生成汇编代码文件,查看.asm文件可以发现这样两端内容:CONSTSEGMENT?_7Base6B DD FLAT:?_R4Base6B; Base:vftableDDFLAT:?f1BaseUAEXXZDDFLAT:?f2BaseUAEXXZDDFLAT:?f3BaseUAEXXZCONSTENDSCONSTSEGMENT?_7Derived6B DD FLAT:?_R4Derived6B; Derived:vftableDDFLAT:?f1DerivedUAEXXZDDFLAT:?f2BaseUAEXXZDDFLAT:?f3DerivedUAEXXZDDFLAT:?f4DerivedUAEXXZCONSTENDS这里说明一下如何在VS2012中生成汇编代码文件。需要进行如下设置:项目 -属性 - 配置属性 - c/c+ - 输出文件 - 右边内容项:汇编输出 -带源代码的程序集(/Fas )。这样在项目里面生成后缀为*.asm 的文件。里面还有注释,有利于分析。从汇编代码可以看出,这是两个常量段,其中分别存放了Base类的虚函数表和Derived类的虚函数表。从中可以发现,虚函数表中的每一项代表了一个函数的入口地址,类型是Double Word。类中每个虚函数的入口地址在虚函数表中的排放顺序,也可以从相应的标识符看出。4.通过访问虚函数表手动调用虚函数既然知道了虚函数表的位置和结构,那么就可以通过访问虚函数表,手动调用虚函数。虽然在利用C+编写程序时没有必要这样做,但如果想了解动态联编的实现机理,请参考如下代码:#include using namespace std;typedef void (*pFunc)();void executeVirtualFunc(void* pObj, int index)pFunc p;unsigned long* pAddr;pAddr=reinterpret_cast(pObj);pAddr=(unsigned long*)*pAddr; /获取虚函数表地址p=(pFunc)pAddrindex; /获取虚函数入口地址_asm mov ecx, pObjp(); /实施函数调用class Baseint i;public:Base()i=0;virtual void f1()coutBases f1()endl;virtual void f2()coutBases f2()endl;virtual void f3()coutBases f3()endl;class Derived:public Baseint j;public:Derived()j=1;virtual void f4()coutDeriveds f4(),j=jendl;void f3()coutDeriveds f3()endl;void f1()coutDeriveds f1()endl;int main()Base b;Derived d;executeVirtualFunc(&b,1);executeVirtualFunc(&d,3);执行executeVirtualFunc(&b,1);就是调用基类对象b的第二个虚函数(b.f2(),执行executeVirtualFunc(&d,3);就是调用子类d的第四个虚函数
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 炉料纯铁销售合同范本
- 邀请学术专家合同协议
- 物业劳务客服合同范本
- 牛肉浸粉采购合同范本
- 酒店员工招聘合同范本
- 物业托管协议补充合同
- 潍坊鸡粪购销合同范本
- 赠予房屋出售合同范本
- 直播行业员工合同范本
- 维修家政团购合同范本
- 2025年中石油考试题大全及答案
- 湖北省黄石市十四中2025年十月质量监测九年级语文试卷(含答案)
- 纯水储罐清洗施工方案
- 北京中医药大学《中医基础理论》期中考试试卷(含答案)
- 油库施工冬季施工方案
- 我国农业数字化技术发展现状与数字经济发展策略
- DB5133∕T 74-2023 甘孜藏餐 通 用规范
- 珠海市辅警笔试真题2025
- 跨境犯罪打击-洞察及研究
- 2026秋季中国东方航空股份有限公司综合管理部卫生保健岗位招聘考试模拟试题及答案解析
- 国际道路应急预案
评论
0/150
提交评论