从汇编层面深度剖析C++虚函数
作者:海枫 发布时间:[ 2017/1/4 11:19:55 ] 推荐标签:虚函数 构造函数
4. 实现运行时多态的关键一步
在造构函数里面设置好的vtable的值,显然,同一类型所有对象内的vtable值都是一样的,并且永远不会改变。下面是main函数生成的汇编代码,它展示了C++如何利用vtable来实现运行时多态。
.globl main
.type main, @function
main:
.LFB3:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
leal 24(%esp), %eax
movl %eax, (%esp)
call _ZN6DeriveC1Ev
leal 24(%esp), %eax
movl %eax, 28(%esp)
movl 28(%esp), %eax
movl (%eax), %eax
movl (%eax), %edx
movl 28(%esp), %eax
movl %eax, (%esp)
call *%edx
movl $0, %eax
leave
ret
.cfi_endproc
andl $-16, %esp
subl $32, %esp
这两句是为局部变量d和bp在堆栈上分配空间,也即如下的语句:
Derive d;
Base *pb;
leal 24(%esp), %eax
movl %eax, (%esp)
call _ZN6DeriveC1Ev
esp+24是变量d的首地址,先将它压到堆栈上,然后调用d的构造函数,相应翻译成C语言则如下:
Derive::Dervice(&d);
leal 24(%esp), %eax
movl %eax, 28(%esp)
这里其实是将&d的值赋给pb,也即:
pb = &d;
关键的代码是下面这一段:
movl 28(%esp), %eax
movl (%eax), %eax
movl (%eax), %edx
movl 28(%esp), %eax
movl %eax, (%esp)
call *%edx
翻译成C语言也传神的那句:
pb->vtable[0](bp);
编译器会记住f虚函数放在vtable的第0项,这是编译时信息。
5. 小结
这里省略了很多关于编译器和C++的细枝未节,是出于讨论方便用的需要。从上面的编译代码可以看到以下信息:
1.每个类都有各有的vtable结构,编译会正确填写它们的虚函数表
2. 对象在构造函数时,设置vtable值为该类的虚函数表
3.在指针或者引用时调用虚函数,是通过object->vtable加上虚函数的offset来实现的。
当然这仅仅是g++的实现方式,它和VC++的略有不同,但原理是一样的。
本文内容不用于商业目的,如涉及知识产权问题,请权利人联系SPASVO小编(021-61079698-8054),我们将立即处理,马上删除。
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11热门文章
常见的移动App Bug??崩溃的测试用例设计如何用Jmeter做压力测试QC使用说明APP压力测试入门教程移动app测试中的主要问题jenkins+testng+ant+webdriver持续集成测试使用JMeter进行HTTP负载测试Selenium 2.0 WebDriver 使用指南