



全文预览已结束
VIP免费下载
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
深入研究虚函数和vtable国防科技大学计算机学院 褚瑞 在面向对象的C+语言中,虚函数(virtual function)是一个非常重要的概念。因为它充分体现了面向对象思想中的继承和多态性这两大特性,在C+语言里应用极广。比如在微软的MFC类库中,你会发现很多函数都有virtual关键字,也就是说,它们都是虚函数。难怪有人甚至称虚函数是C+语言的精髓。 那么,什么是虚函数呢,我们先来看看微软的解释: 虚函数是指一个类中你希望重载的成员函数,当你用一个基类指针或引用指向一个继承类对象的时候,你调用一个虚函数,实际调用的是继承类的版本。摘自MSDN 这个定义说得不是很明白。MSDN中还给出了一个例子,但是它的例子也并不能很好的说明问题。我们自己编写这样一个例子:#include stdio.h#include conio.hclass Parentpublic:char data20;void Function1();virtual void Function2(); / 这里声明Function2是虚函数parent;void Parent:Function1()printf(This is parent,function1n);void Parent:Function2()printf(This is parent,function2n);class Child:public Parentvoid Function1();void Function2(); child;void Child:Function1()printf(This is child,function1n);void Child:Function2()printf(This is child,function2n);int main(int argc, char* argv)Parent *p;/ 定义一个基类指针if(_getch()=c)/ 如果输入一个小写字母cp=&child;/ 指向继承类对象elsep=&parent;/ 否则指向基类对象p-Function1(); / 这里在编译时会直接给出Parent:Function1()的 入口地址。p-Function2(); / 注意这里,执行的是哪一个Function2?return 0; 用任意版本的Visual C+或Borland C+编译并运行,输入一个小写字母c,得到下面的结果:This is parent,function1This is child,function2 为什么会有第一行的结果呢?因为我们是用一个Parent类的指针调用函数Fuction1(),虽然实际上这个指针指向的是Child类的对象,但编译器无法知道这一事实(直到运行的时候,程序才可以根据用户的输入判断出指针指向的对象),它只能按照调用Parent类的函数来理解并编译,所以我们看到了第一行的结果。 那么第二行的结果又是怎么回事呢?我们注意到,Function2()函数在基类中被virtual关键字修饰,也就是说,它是一个虚函数。虚函数最关键的特点是“动态联编”,它可以在运行时判断指针指向的对象,并自动调用相应的函数。如果我们在运行上面的程序时任意输入一个非c的字符,结果如下:This is parent,function1This is parent,function2 请注意看第二行,它的结果出现了变化。程序中仅仅调用了一个Function2()函数,却可以根据用户的输入自动决定到底调用基类中的Function2还是继承类中的Function2,这就是虚函数的作用。我们知道,在MFC中,很多类都是需要你继承的,它们的成员函数很多都要重载,比如编写MFC应用程序最常用的CView:OnDraw(CDC*)函数,就必须重载使用。把它定义为虚函数(实际上,在MFC中OnDraw不仅是虚函数,还是纯虚函数),可以保证时刻调用的是用户自己编写的OnDraw。虚函数的重要用途在这里可见一斑。 在了解虚函数的基础之上,我们考虑这样的问题:一个基类指针必须知道它所指向的对象是基类还是继承类的示例,才能在调用虚函数时“自动”决定应该调用哪个版本,它是如何知道的?有些讲C+的书上提到,这种“动态联编”的机制是通过一个“vtable”实现的,vtable是什么?微软在关于COM的文档里这样描述: vtable是指一张函数指针表,如同C+中类的实现一样,vtable中的指针指向一个对象支持的接口成员函数。 摘自MSDN 很遗憾,微软这次还是没有把问题说清楚,当然,上面的文档本来就是关于COM的,与我们关心的问题不同。 那么vtable是什么?我们先来看看下面的实验: 在前面的示例程序中加一句 printf(“%d”,sizeof(Child); 运行,然后去掉Function2()前的virtual关键字,再运行,得到这样的结果:当Function2定义成虚函数的时候,结果是24,否则结果是20。也就是说,如果Function2不是虚函数,一个Child类的示例所占空间的大小仅仅是它的成员变量data数组的大小,如果Function2是虚函数,结果多了4个字节。我们使用的是32位的Visual C+ 6.0,4个字节恰好是一个指针,或者是一个整数所占的空间。 那么这多出来的四个字节究竟起到了什么作用? 用Visual C+打开前面的示例程序,在main函数中p-Function1(); 一句前面按F9设断点,按F5开始调试,输入一个小写c,程序停到了我们设的断点上。找到Debug工具条,按Disassembly按钮,如图所示: 我们看到了反汇编后的代码。由上图可见,对Function1和Function2的调用反汇编后生成的代码截然不同。Function1不是虚函数,因此对它的调用仅仅被编译成为一条call指令,转向Parent:Function1子程序;而Function2是虚函数,它的代码要复杂一些,我们来仔细分析:45: p-Function2(); 004012CA mov eax,dword ptr ebp-4/ eax就是我们的p指针004012CD mov edx,dword ptr eax/ edx取child对象头部四个字节004012CF mov esi,esp004012D1 mov ecx,dword ptr ebp-4/ 可能要检查栈,不管它004012D4 call dword ptr edx/ 注意这里,调用了child对象头部的一个函数指针004012D6 cmp esi,esp004012D8 call _chkesp (004013b0)这里最关键的一句是call dword ptredx,edx是child对象头部,前面我们分析过了,child对象共有24字节,其中成员变量占用20字节,还有4个字节作用未知。现在从这段汇编代码上看,那4个字节很可能就是child对象开头的这个函数指针,因为编译器并不知道我们的成员变量data是做什么用的,更不可能把data的任何一部分当成一个函数指针来处理。那么这个函数指针会跳转到那里去呢?我们按F10单步运行到这个call指令,然后按F11跟进去:00401032 jmp Parent:Function2 (0040bfe0)00401037 jmp Parent:Parent (004010d0) 0040103C jmp Child:Function2 (00401250)00401041 jmp Child:Child (004011c0)光标停在了第三行,40103C的地方,执行这里的jmp指令后,又跳转到Child:Function2的位置,从而得到我们上面所看到的结果。这并不是最终的结论,我们看看40103C周围的几行代码,连续几行全都是jmp指令,这是什么程序结构?有汇编语言编程经验的朋友可能会想起来了,这是一张入口表,分别存放着到几个重要函数的跳转指令!我们再回去看看微软对于vtable的描述:vtable是指一张函数指针表,(如同C+中类的实现一样,)vtable中的指针指向(一个对象支持的接口)成员函数。打括号的字不要看,这句话的主干就是:vtable是一张函数指针表,指向成员函数。种种事实证明,上面的四行代码就是我们要找的这个vtable!现在我们应该对虚函数的原理有一个认识了。每个虚函数都在vtable中占了一个表项,保存着一条跳转到它的入口地址的指令(实际上就是保存了它的入口地址)。当一个包含虚函数的对象(注意,不是对象的指针)被创建的时候,它在头部附加一个指针,指向vtable中相应位置。调用虚函数的时候,不管你是用什么指针调用的,它先根据vtable找到入口地址再执行,从而实现了“动态联编”。而不像普通函数那样简单地跳转到
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 玉林市福绵区特岗教师招聘笔试真题2024
- 昆明市公安局呈贡分局勤务辅警招聘笔试真题2024
- 石大学前儿童保育学课件1-2呼吸系统
- 生物打印再生组织-洞察阐释
- 对数函数及其性质(第一课时)教学设计教学设计
- 2025至2030年中国电力系统接线装置行业投资前景及策略咨询报告
- 2025至2030年中国玻璃专用金刚石锯片行业投资前景及策略咨询报告
- 第二节发生在肺内的气体交换教学设计
- 人工智能+教育论文
- 2025至2030年中国滚柱式单向超越离合器行业投资前景及策略咨询报告
- 2025年4月八大员-劳务员练习题库与参考答案解析
- 2025-2030肺癌手术行业市场现状供需分析及投资评估规划分析研究报告
- 农村饮水安全工程可行性研究报告
- 一级注册建筑师真题含答案2025年
- 工业大数据的安全与隐私保护-洞察阐释
- 上海教育版数学八年级上册《直角三角形》导学案
- 数字经济背景下的财务共享中心建设
- 2024年江苏徐州中考地理试卷真题及答案详解(精校打印)
- 2025年安全月主要责任人讲安全课件三:安全月主题宣讲课件
- 病原微生物识别技巧试题及答案
- 初中语文第23课《“蛟龙”探海》课件-2024-2025学年统编版语文七年级下册
评论
0/150
提交评论