网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > C/C++
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.C++习题与解析(重载-03).
.数据结构题集--数组(二维数组).
.C++辨析系列之前言.
.C++箴言:绝不在构造或析构期调用.
.显卡计算.
.又一个弹球游戏.
.C语言:黑客学员必修课(一).
.C++ 扩展和嵌入 Python(1).
.编程资源收集.
.第 1 章 贪婪算法.
.C++ 泛型编程系列讲座之实施.
.C/C++:如何在程序中加载JPG图片?.
.C语言教程第四章: 数组.
.用 c 写 CGI 程序简要指南.
.在Listboxes中加背景图.
.C语言基础教程(六)Turbo .
.C/C+语言struct深层探索.
.用C++控制DVD/CD驱动器的开关.
.C++程序设计之四书五经(上篇).
.C语言编程.

C++对象布局及多态实现之成员函数的调用

发表日期:2008-3-8


从这部分开始我们除了利用内存的信息打印来进行探索外,更多的会通过跟踪和观察编译器产生的汇编代码来理解编译器对这些语言特性的实现方式。汇编方面知识的讨论超出了本文的范围,我只对和我们讨论相关的汇编代码进行解析。
理解本文要讨论的知识并不需要有很完整的汇编知识,但必须了解起码的概念。 下面我们看看引入虚继续后的影响。为了有所对比我们首先看看普通成员函数的调用情况。 执行如下代码,它包括了对象的普通成员函数调用,类的静态成员函数调用、通过指针调用普通成员函数: C010 obj; PRINT_OBJ_ADR(obj) obj.foo(); C012::sfoo(); C010 * pt = &obj; pt-> foo(); 结果如下: obj's address is : 0012F843 这是obj对象的内存地址。 首先我们看看对象的普通成员函数调用,obj.foo();,对应的汇编代码为: 00422E09 lea ecx,[ebp+FFFFF967h] 00422E0F call 0041E289 第1行把对象的地址存入ecx寄存器,执行完这行指令后,我们要以看到ecx中的值为0x0012F843,就是前面打印出的值。假如函数需要传递参数,我们还会在前面看到一些push指令。在第2行我们可以看到call的是一个直接的地址,这也就是静态绑定。即函数的调用地址在编译时已经被编译器决议。 跟踪进去我们要以看到是一条跳转指令,继续执行可以看到真正的函数代码部分,如下(注:为了讨论方便我在第行前面加了一个行号):   01 00425FE0 push ebp   02 00425FE1 mov ebp,esp   03 00425FE3 sub esp,0CCh   04 00425FE9 push ebx   05 00425FEA push esi   06 00425FEB push edi   7 00425FEC push ecx   08 00425FED lea edi,[ebp+FFFFFF34h]   09 00425FF3 mov ecx,33h   10 00425FF8 mov eax,0CCCCCCCCh   11 00425FFD rep stos dWord ptr [edi]   12 00425FFF pop ecx   13 00426000 mov dword ptr [ebp-8],ecx   14 00426003 mov eax,dword ptr [ebp-8]   15 00426006 mov byte ptr [eax],2   16 00426009 pop edi
  17 0042600A pop esi   18 0042600B pop ebx   9 0042600C mov esp,ebp   20 0042600E pop ebp   21 0042600F ret
我们看看第7行,把ecx寄存器入栈,后面4行初始化了函数的堆栈中的保存局部变量的部分。第12行弹出ecx值,到这里时ecx的值保持为在函数调用前存入的对象内存地址,第13行就是保存this指针的值,作为一个局部变量。这样我们就知道了VC7.1不是象传递普通函数那样通过压栈来传递this 指针,而是通过ecx寄存器来传递。第14、15行利用这个this指针给对象的成员变量进行了赋值。 再看看静态成员函数调用的汇编代码:      00422E14 call 0041DD84 非常直接,因为它不需要处理this指针,跟踪到函数的汇编代码,可以看到同样不需要处理this指针。具体的代码这里就不列出来了。 再看看通过指针调用普通成员函数pt-> foo();,产生的汇编代码如下:    00422E25 mov ecx,dword ptr [ebp+FFFFF958h]    00422E2B call 0041E289 和通过对象调用普通成员函数的代码差不多。不过存对象地址到ecx寄存器地,是通过解引用pt指针来找到对象地址的。
上一篇:Delphi 插件创建、调试与使用应用程序扩展 人气:374
下一篇:C++对象布局及多态实现之带虚函数的类 人气:634
浏览全部C/C++的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐