this指针
问题切入
我们在学习C++的时候,会了解到面向对象的思想以及类与对象。
简单的来说,类是一个设计图纸:我们现实客观世界的实体经过分析和抽象之后得到我们主观世界里的抽象类别,也就是你脑子里的各种idea,当你把脑子里的这种抽象类别设计出来之后,就得到了类(class),最后对class进行实例化得到我们的对象(object)。
整个过程可以用如下的图来理解:
关于对象的模型,可以存在如下两种方案:
毫无疑问,为了节省内存空间,我们肯定更倾向于方案二,也就是各个对象共用代码区。
那么,问题来了:
我们在调用同一个类的不同对象的成员函数时,成员函数如何知道要访问哪个对象的数据成员呢?
什么是this指针?
没错,上述问题的答案就是我们今天要讲的this指针。
每个对象都拥有一个this指针,this指针记录对象的内存地址,当我们调用成员函数时,成员函数默认第一个参数为T* const register this,大多数编译器通过ecx寄存器传递this指针,通过 this 这个隐式参数可以访问该对象的数据成员。
注:有关ecx寄存器其实就是C++的调用约定:_thiscall:
_thiscall 是一种C++语言特有的调用方式,用于类成员函数的调用约定。
如果参数确定:
this指针存放于 ECX 寄存器,函数自身清理堆栈;
如果参数不确定:
this指针在所有的参数入栈后再入栈,调用者清理堆栈。
_thiscall 不是关键字,程序员不能使用。
this指针怎么用?
说了这么多,可能大家还不是很了解this指针具体怎么使用,我们来看如下的简单代码示例:
#include <iostream>
using namespace std;
class CGoods
{
private:
char Name[20];
int Amount;
float Price;
float Total;
public:
void RegisterGoods(const char* name, int amount, float price);
int GetAmount()
{
return Amount;
}
float GetTotal()
{
return Total;
}
};
void CGoods::RegisterGoods(const char* name, int amount, float price)
{
strcpy_s(Name,20,name);
Amount = amount;
Price = price;
Total = Amount * Price;
}
int main()
{
CGoods tea;
CGoods book;
tea.RegisterGoods("Rea tea",3,50.5);
book.RegisterGoods("Little Prince",5,13.14);
return 0;
}
可以看到我们创建了有关CGoods
类的两个对象:tea
和book
;
那么在执行tea.RegisterGoods()
和book.RegisterGoods()
的时候,我们怎么知道该调用的是tea还是book呢?
这就不得不提编译器对类进行编译的步骤:
编译器对程序员自己设计的类进行编译时分为三步;
1、识别和记录类体中属性的名称,类型和访问限定;
2、识别和记录类体中函数原型(返回类型+函数名+参数列表)、形参的默认值、访问限定;
3、改写在类中定义函数的参数列表和函数体,改写对象调用成员函数的形式;
其中最重要的就是最后一步改写了:
对我们上面的代码改写之后:
#include <iostream>
using namespace std;
class CGoods
{
private:
char Name[20];
int Amount;
float Price;
float Total;
public:
//void RegisterGoods(CGoods* const this,const char* name, int amount, float price)
void RegisterGoods(const char* name, int amount, float price);
//int GetAmount(CGoods* const this)
int GetAmount()
{
return Amount;
}
//float GetTotal(CGoods* const this)
float GetTotal()
{
return Total;
}
};
//void CGoods::RegisterGoods(CGoods* const this, const char* name, int amount, float price)
void CGoods::RegisterGoods(const char* name, int amount, float price)
{
strcpy_s(Name,20,name);
Amount = amount;
Price = price;
Total = Amount * Price;
}
int main()
{
CGoods tea;
CGoods book;
//RegisterGoods(&tea,"Rea tea",3,50.5)
tea.RegisterGoods("Rea tea",3,50.5);
//RegisterGoods(&book,"Little Prince",5,13.14)
book.RegisterGoods("Little Prince",5,13.14);
return 0;
}
可以看到,所谓的编译器改写:
即是在所有成员函数的参数列表添加了一个T* const this
参数;
注:
1、这个T
是类的名称,比如你定义的类名是CGoods
,那么这里的参数即为:CGoods* const this
;
2、这个const
不可缺少,它意味着this指针本身不可更改,也就是说,编译器一旦改写赋予了这个this指针,this指针绑定的对象就不可以改变。
this指针的注意点
-
C++中this关键字是一个指向对象自己的一个常量指针,不能给this赋值;
-
只有成员函数才有this指针,友元函数不是类的成员函数,没有this指针;
-
同样静态函数也是没有this指针的,静态函数如同静态变量一样,不属于具体的哪一个对象;
-
this指针作用域在类成员函数内部,在类外也无法获取;
-
this指针并不是对象的一部分,this指针所占的内存大小是不会反应在sizeof操作符上的。
参考资料
【1】KeepHopes.C++this指针详解.cnblogs.2019.06.07
【2】C++中的this指针 | 菜鸟教程
【3】C++this指针(百度百科)