C++对象布局及多态实现之动态和强制转换

C++对象布局及多态实现之动态和强制转换,第1张

C++对象布局及多态实现之动态和强制转换,第2张

从这一部分开始,我们不仅要利用内存中打印的信息进行探究,还要跟踪观察编译器生成的汇编代码,了解编译器是如何实现这些语言特性的。汇编知识的讨论超出了本文的范围。我只分析与我们讨论相关的汇编代码。要理解本文要讨论的知识,不需要有完整的汇编知识,但必须知道基本概念。

让我们来看看引入虚拟继承的影响。为了比较,我们先来看看普通成员函数的调用。

执行下面的代码,包括对象的普通成员函数调用、类的静态成员函数调用和通过指针的普通成员函数调用:
C010 obj;
PRINT _ OBJ _ ADR(obj)
obj . foo();
C012::sfoo();
C010 * pt = & obj;
pt-> foo();
结果如下:
obj的addressis: 0012f843
这是obj对象的内存地址。
首先我们来看对象的普通成员函数调用,obj . foo();,对应的汇编代码为:
00422e09leaecx,[EBP+fffff 967h]
00422 E0 fall 0041 e 289。

第1行存储ecx寄存器中对象的地址。执行完这行指令后,我们会看到ecx中的值是0x0012F843,这是前面打印出来的值。如果函数需要传递参数,我们也会在前面看到一些推送指令。在第2行,我们可以看到调用是一个直接地址,这是静态绑定。也就是说,函数的调用地址是由编译器在编译时决定的。

跟踪是一个跳转指令。如果继续执行,可以看到真正的函数代码,如下(注:为了讨论方便,我在第一行前面加了行号):
01 00425 FE0推送EBP
02 00425 FE1 MOV EBP,esp
03 00425FE3 sub esp,0CCh
04 00425FE9推送ebx
05 00425FEA推送esi [/br [ebp+ffffff 34h]
09 00425 ff3 mov ecx,33h
10 00425FF8 mov eax,0 ccccccccch
11 00425 ffd rep stos dword ptr[EDI]
12 00425 fff pop ecx
13 00426000 mov dword ptr[ebp-8],ecx

让我们看看第7行,将ecx寄存器放入堆栈。最后四行初始化函数堆栈中保存局部变量的部分。ecx值在第12行弹出。当您到达这里时,ecx值被保存为调用函数之前存储的对象内存地址。第13行是将这个指针的值保存为一个局部变量。这样我们就知道,VC7.1不是像普通函数那样通过压栈来传递这个指针,而是通过ecx寄存器。第14行和第15行使用this指针为对象的成员变量赋值。

看静态成员函数调用的汇编代码:
00422E14 call 0041DD84。

很直接,因为它不需要处理这个指针,而且可以看出它也不需要处理这个指针,追溯到函数的汇编代码之后。这里没有列出具体的代码。

看看通过指针调用普通成员函数pt-> foo()。,生成的汇编代码如下:
00422e25mov ecx,dword ptr[EBP+fffff 958h]
00422 e 2 ball 0041 e 289

类似于通过对象调用普通成员函数的代码。然而,将对象地址存储到ecx寄存器中是通过解引用pt指针来找到对象地址。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C++对象布局及多态实现之动态和强制转换

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情