在C++编程中,this指针是经常需要用到,特别是形参与类结构成员具有相同名称时;我们都知道this是指向对象本身,那它是怎么实现呢?
先看一段源代码,如下:
#include <iostream>
using namespace std;
class people
{
public:
int a;
int b;
people(int a, int b);
};
people::people(int a, int b)
{
this->a = a;
this->b = b;
}
int main()
{
people e1(2, 3);
return 0;
}
(1)main函数
从源代码中可以看到,在类people的构造函数people(int a, int b)有使用到this;先来看看main函数的汇编:
main:
00401080 push ebp
00401081 mov ebp,esp
00401083 sub esp,48h
00401086 push ebx
00401087 push esi
00401088 push edi
00401089 lea edi,[ebp-48h]
0040108C mov ecx,12h
00401091 mov eax,0CCCCCCCCh
00401096 rep stos dword ptr [edi]
00401098 push 3
0040109A push 2
0040109C lea ecx,[ebp-8]
0040109F call @ILT+0(people::people) (00401005)
004010A4 xor eax,eax
004010A6 pop edi
004010A7 pop esi
004010A8 pop ebx
004010A9 add esp,48h
004010AC cmp ebp,esp
004010AE call __chkesp (004081a0)
004010B3 mov esp,ebp
004010B5 pop ebp
004010B6 ret
其中最主要的是上面蓝色部分,即people e1(2, 3);主要功能:
(1)参数压栈
(2)保存e1对象的地址到ecx;(即this指针的前身)
(3)call;
其中ILT是静态函数跳转的表,从汇编中可以看到上述源代码的ILT如下:
@ILT+0(??0people@@QAE@HH@Z):
00401005 jmp people::people (00401030)
@ILT+5(?id@?$ctype@G@std@@$D):
0040100A jmp std::ctype<unsigned short>::id (00401110)
@ILT+10(?id@?$ctype@G@std@@$E):
0040100F jmp std::ctype<unsigned short>::id (004011b0)
@ILT+15(_main):
00401014 jmp main (00401080)
(2)构造函数people
下面进入people构造函数,反汇编如下:
people::people:
00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,44h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 push ecx
0040103A lea edi,[ebp-44h]
0040103D mov ecx,11h
00401042 mov eax,0CCCCCCCCh
00401047 rep stos dword ptr [edi]
00401049 pop ecx
0040104A mov dword ptr [ebp-4],ecx
0040104D mov eax,dword ptr [ebp-4]
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [eax],ecx
00401055 mov edx,dword ptr [ebp-4]
00401058 mov eax,dword ptr [ebp+0Ch]
0040105B mov dword ptr [edx+4],eax
0040105E mov eax,dword ptr [ebp-4]
00401061 pop edi
00401062 pop esi
00401063 pop ebx
00401064 mov esp,ebp
00401066 pop ebp
00401067 ret 8
通过main函数可以知道,对象e1的地址是保存在ecx中,于是:
00401039 push ecx
。。。
00401049 pop ecx
0040104A mov dword ptr [ebp-4],ecx
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [eax],ecx
00401058 mov eax,dword ptr [ebp+0Ch]
0040105B mov dword ptr [edx+4],eax
总结:
通过上述分析,可以知道,this指针就是存放在当前成员函数的[ebp-4]位置;
先看一段源代码,如下:
#include <iostream>
using namespace std;
class people
{
public:
int a;
int b;
people(int a, int b);
};
people::people(int a, int b)
{
this->a = a;
this->b = b;
}
int main()
{
people e1(2, 3);
return 0;
}
(1)main函数
从源代码中可以看到,在类people的构造函数people(int a, int b)有使用到this;先来看看main函数的汇编:
main:
00401080 push ebp
00401081 mov ebp,esp
00401083 sub esp,48h
00401086 push ebx
00401087 push esi
00401088 push edi
00401089 lea edi,[ebp-48h]
0040108C mov ecx,12h
00401091 mov eax,0CCCCCCCCh
00401096 rep stos dword ptr [edi]
00401098 push 3
0040109A push 2
0040109C lea ecx,[ebp-8]
0040109F call @ILT+0(people::people) (00401005)
004010A4 xor eax,eax
004010A6 pop edi
004010A7 pop esi
004010A8 pop ebx
004010A9 add esp,48h
004010AC cmp ebp,esp
004010AE call __chkesp (004081a0)
004010B3 mov esp,ebp
004010B5 pop ebp
004010B6 ret
其中最主要的是上面蓝色部分,即people e1(2, 3);主要功能:
(1)参数压栈
(2)保存e1对象的地址到ecx;(即this指针的前身)
(3)call;
其中ILT是静态函数跳转的表,从汇编中可以看到上述源代码的ILT如下:
@ILT+0(??0people@@QAE@HH@Z):
00401005 jmp people::people (00401030)
@ILT+5(?id@?$ctype@G@std@@$D):
0040100A jmp std::ctype<unsigned short>::id (00401110)
@ILT+10(?id@?$ctype@G@std@@$E):
0040100F jmp std::ctype<unsigned short>::id (004011b0)
@ILT+15(_main):
00401014 jmp main (00401080)
(2)构造函数people
下面进入people构造函数,反汇编如下:
people::people:
00401030 push ebp
00401031 mov ebp,esp
00401033 sub esp,44h
00401036 push ebx
00401037 push esi
00401038 push edi
00401039 push ecx
0040103A lea edi,[ebp-44h]
0040103D mov ecx,11h
00401042 mov eax,0CCCCCCCCh
00401047 rep stos dword ptr [edi]
00401049 pop ecx
0040104A mov dword ptr [ebp-4],ecx
0040104D mov eax,dword ptr [ebp-4]
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [eax],ecx
00401055 mov edx,dword ptr [ebp-4]
00401058 mov eax,dword ptr [ebp+0Ch]
0040105B mov dword ptr [edx+4],eax
0040105E mov eax,dword ptr [ebp-4]
00401061 pop edi
00401062 pop esi
00401063 pop ebx
00401064 mov esp,ebp
00401066 pop ebp
00401067 ret 8
在讲解之前,先来看看执行到“00401039 push ecx”时堆栈的布局:
通过main函数可以知道,对象e1的地址是保存在ecx中,于是:
00401039 push ecx
。。。
00401049 pop ecx
0040104A mov dword ptr [ebp-4],ecx
就是把ecx的值赋给[ebp-4],即上图this所在的位置;到这里我们就清楚了this的来历;
下面的3句汇编是实现this->a = a;
00401050 mov ecx,dword ptr [ebp+8]
00401053 mov dword ptr [eax],ecx
下面的3句汇编是实现this->b = b;
00401058 mov eax,dword ptr [ebp+0Ch]
0040105B mov dword ptr [edx+4],eax
总结:
通过上述分析,可以知道,this指针就是存放在当前成员函数的[ebp-4]位置;