用汇编的眼光看C++(之虚函数)
来源:互联网 发布:linux 网卡驱动 编辑:程序博客网 时间:2024/04/29 20:44
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
虚函数是面向对象设计中的一个重要内容。它的出现使得我们只需要相同的接口函数,并可以得到不同的生成结果。但是有些朋友却知其然,不知其所以然,为什么会出现这样的结果,我们可以用一段代码说明问题。首先,我们先定义两个基本类型,一个是employee,一个是manager,看过前面一片博客的朋友应该都有点印象:
class employee{public:employee() { }~employee() {}virtual void print() const { printf("employee!\n");}};class manager : public employee{public:manager() {}~manager() {}void print() const {printf("manager!\n");}};我们看到,和前面出现的成员函数稍微有一些不同,这里的print函数之前出现了virtual。然而正是这个virtual发挥了巨大的作用。可以毫不夸张地说,没有虚函数,基本上就没有设计模式,也就无法体现C++语言在面向对象设计中的巨大优越性。下面我们看看这个virtual是怎样发挥作用的?
76: employee p;0040128D lea ecx,[ebp-10h]00401290 call @ILT+45(employee::employee) (00401032)00401295 mov dword ptr [ebp-4],077: manager m;0040129C lea ecx,[ebp-14h]0040129F call @ILT+65(manager::manager) (00401046)004012A4 mov byte ptr [ebp-4],178: employee* e = &p;004012A8 lea eax,[ebp-10h]004012AB mov dword ptr [ebp-18h],eax79: e->print();004012AE mov ecx,dword ptr [ebp-18h]004012B1 mov edx,dword ptr [ecx]004012B3 mov esi,esp004012B5 mov ecx,dword ptr [ebp-18h]004012B8 call dword ptr [edx]004012BA cmp esi,esp004012BC call __chkesp (00408870)80: e = &m;004012C1 lea eax,[ebp-14h]004012C4 mov dword ptr [ebp-18h],eax81: e->print();004012C7 mov ecx,dword ptr [ebp-18h]004012CA mov edx,dword ptr [ecx]004012CC mov esi,esp004012CE mov ecx,dword ptr [ebp-18h]004012D1 call dword ptr [edx]004012D3 cmp esi,esp004012D5 call __chkesp (00408870)82: }上面是一段函数调用的代码,代码可以稍微有点长。不过没有关系,我们可以按照代码的行数一行一行地去进行说明和理解。
76行: 我们创建了employee类型的一个变量p,这个可以从后面的employee的构造函数可以看出来
77行: 我们创建了manager类型的一个变量,这个也可以从后面的manager的构造函数看出
78行: 我们创建一个指针临时变量e,它保存了变量p的地址,这一句也比较简单
79行: 我们发现79句下面共有7句汇编,其中第三句、第六句、第七句是平衡堆栈的时候用的,和我们的调用没有关系。那么call的edx是什么东西呢?原来函数调用的顺序是这样的:edx -> [ecx] ->[ebp-0x18],不知道大家看明白了没有。在内存的第一个字节记录一个指向print函数指针的指针,也就是edx。通过这个edx,我们就可以查找到位于edx地址的内容是什么。后来我们提取出来后发现[edx]的内容正是我们要查找的print函数地址。这里相当于一个二次寻址的过程。
80行: 我们重新对临时变量e进行了赋值,此时e保存的是变量m的地址
81行: 我们发现此时的寻找过程和79行惊奇地一致,原因就在于edx的内容不同罢了。也就是指向函数指针的指针发生了变化而已。
试想一下,如果没有这个virtual函数,以上这段代码会发生什么差别呢?
76: employee p;0040127D lea ecx,[ebp-10h]00401280 call @ILT+45(employee::employee) (00401032)00401285 mov dword ptr [ebp-4],077: manager m;0040128C lea ecx,[ebp-14h]0040128F call @ILT+65(manager::manager) (00401046)00401294 mov byte ptr [ebp-4],178: employee* e = &p;00401298 lea eax,[ebp-10h]0040129B mov dword ptr [ebp-18h],eax79: e->print();0040129E mov ecx,dword ptr [ebp-18h]004012A1 call @ILT+5(employee::print) (0040100a)80: e = &m;004012A6 lea ecx,[ebp-14h]004012A9 mov dword ptr [ebp-18h],ecx81: e->print();004012AC mov ecx,dword ptr [ebp-18h]004012AF call @ILT+5(employee::print) (0040100a)82: }很遗憾,这里就没有了动态查找的过程,所有的打印函数最终都指向了函数employee::print,此时多态性也不复存在了。
【预告: 下一片博客将介绍类中的静态变量和静态函数】
- 用汇编的眼光看C++(之虚函数)
- 用汇编的眼光看C++(之虚函数)
- 用汇编的眼光看C++(之虚函数)
- 用汇编的眼光看C++(之虚函数)
- 用汇编的眼光看C++(之特殊函数)
- 用汇编的眼光看c++(之模板函数)
- 用汇编的眼光看c++(之模板函数)
- 用汇编的眼光看C++(之特殊函数)
- 用汇编的眼光看c++(之模板函数)
- 用汇编的眼光看C++(之特殊函数)
- 用汇编的眼光看C++(之特殊函数)
- 用汇编的眼光看c++(之模板函数)
- 用汇编的眼光看C++(之特殊函数)
- 用汇编的眼光看c++(之模板函数)
- 用汇编的眼光看C++(之嵌入汇编)
- 用汇编的眼光看C++(之嵌入汇编)
- 用汇编的眼光看C++(之嵌入汇编)
- 用汇编的眼光看C++(之嵌入汇编)
- Ubuntu10.10上配置安装LAMP
- iconv 的技巧
- 第一次当审稿人
- win7下myeclipse/eclipse使用subclipse进行checkout时自动关闭问题
- Ckeditor编辑器在JAVA中的使用与配置
- 用汇编的眼光看C++(之虚函数)
- linux学习笔记(十) linux下查找文件、字符串
- res/ 资源(Resource)目录简介
- js-window属性说明
- Empty Recycle Bin by vb script - 用VB脚本清空Windows回收站
- Qt —— QVariant
- C/C++封装库ocicpplib调用Oracle存储过程的方法
- 你不得不熟悉的字符串处理函数
- 【Internet信息服务】-【默认网站】的端口调整