在谈this指针时,我们先看一个例子,相必大家都在银行的自助设备上取过钱,我们现在用C语言简单的模拟下这个场景,先定义一个结构体:
struct Account{
char acc[25]; //账号
int blance; //余额,备注:为了方便后面说明,这里金额用整形表示,在实际中应该用浮点数表示
};
在自助设备上我们可以进行取款、存款等操作,下面我们用代码来模拟这两个操作:
//取款
void CWD(Account *arg_acc, int arg_amt){
arg_acc->blance = arg_acc->blance - arg_amt; //这里简单模拟下,就不判断金额不够的情况
}
//存款
void DEP(Account *arg_acc, int arg_amt){
arg_acc->blance = arg_acc->blance + arg_amt;
}
int _tmain(int argc, _TCHAR* argv[])
{
Account acc1 = {"123456", 0};
DEP(&acc1, 100);
CWD(&acc1, 50);
printf("blance of account %s is %.2d\n", acc1.acc, acc1.blance);
return 0;
}
代码最后输出结果:blance of account 123456 is 50
从上面例子我们可以看出,存取款都有个Account *arg_acc参数,保存着acc1结构体的首地址,我们想有没有一个方法能够让编译器自动帮我们传入结构体的首地址,这样我们可以少写很多代码,也许一两个函数你感受不到,当写的函数多了就会有深刻的体会。很荣幸的告诉你,C++编译器实现该方法,下面我们来看个例子:
struct Account_cpp{
char acc[25];
int blance;
void CWD(int arg_amt){
this->blance = this->blance - arg_amt;
}
void DEP(int arg_amt){
this->blance = this->blance + arg_amt;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Account_cpp acc1 = {"123456", 0};
acc1.DEP(100);
acc1.CWD(50);
printf("blance of account %s is %.2d\n", acc1.acc, acc1.blance);
return 0;
}
代码最后输出结果:blance of account 123456 is 50
上面的例子输出结果和第一个例子一样。我们可以看出CWD和DEP两个方法都没有传入结构体首地址的形参,只是多了个this指针。那么this指针会不会就是保存结构体的首地址呢?为了证实我们的猜想,我们需要看编译后的汇编代码。
acc1.DEP(100); //源代码
00411B53 push 64h
00411B55 lea ecx,[acc1] //[acc1]是vs编辑器方便我们看,故显示对应的符号,acc1保存acc1结构体首地址
00411B58 call Account_cpp::DEP (41153Ch)
如果不会汇编也没关系,我现在给大家大致解释下这几行代码,第一行是我们的源代码,第二行开始就是汇编代码,第二行意思是将数值100(64实际上就是100的十六进制值)压入栈中,第二行的意思就是将结构体acc1变量的首地址保存到ecx寄存器中。第三行代码就是调用DEP函数。在DEP函数就能从栈中取出参数100,在ecx寄存器中取出结构体首地址放到this里,并将100保存到由this指针指向的结构体blance成员变量中。
00411C80 mov dword ptr [this],ecx //该行代码就是DEP函数里的一条汇编代码,含义就是将ecx(即acc1的首地址)保存到this指针里
下面我们看看acc1.CWD(50);对应的汇编代码,是不是也是把结构体的首地址传入的ecx寄存器中。
acc1.CWD(50); //源代码
00411B5D push 32h
00411B5F lea ecx,[acc1]
00411B62 call Account_cpp::CWD (411537h)
从第三行就可以看出在调用CWD函数时也会把acc1结构体的首地址传入ecx中。实际在C++编译器中,只要把函数写在结构体或者类中,在函数调用时都会把结构体首地址通过ecx寄存器传入到函数里,即使该函数里没有用到this指针。