文章目录
前言
class Date
{
public :
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
void SetDate(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1, d2;
d1.SetDate(2022, 4, 13);
d2.SetDate(2022, 4, 14);
d1.Display();
d2.Display();
return 0;
}
关于以上的代码,不知大家是否会有这样的一个疑问??
从代码本身而言:
d1.Display()和d2.Display()可以很清晰观察到其函数调用的对象!!!
从函数本身而言:
Date类中的两个成员函数,其函数体中没有任何关于对象的信息,那么在调用函数时,函数是如何辨别是设置d1对象,还是d2对象呢???
那么C++上,我们无法理解,咱们可以C语言的代码上进行对比
typedef struct Date
{
int _year;
int _month;
int _day;
}Date;
void Display(Date* d)
{
printf("%d-%d-%d\n", d->_year, d->_month, d->_day);
}
void SetDate(Date* d, int year, int month, int day)
{
d->_year = year;
d->_month = month;
d->_day = day;
}
int main()
{
Date d1,d2;
SetDate(&d1, 2022, 4, 13);
SetDate(&d2, 2022, 4, 14);
Display(&d1);
Display(&d2);
return 0;
}
细心的铁铁们,就可以发现在两段代码对比,其实就差了一个指针!!!
那么C++这段代码就真的没有指针了吗?
实则,C++是通过引入this指针来解决该问题的!!!
一、this指针定义
C++编译器给每个“非静态的成员函数”增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在该函数体所有成员变量的操作,都是通过该指针去访问,只不过所有的操作对于用户是透明,即用户不需要来传递,编译器自动完成。
将this指针添加上去,也仍为正确!(注:但不能在形参列表中添加)
二、 this指针的特征
1.this指针的类型,类类型 * const(如图一日期类中,当前this类型则为Date * const),其实也表明了this的指向是不可修改的
2.this指针本质上是一个成员函数的形参,是对象调用成员函数时,将对象地址传参给this指针这一形参,故对象中不存储this指针
3.this指针是成员函数第一个隐含的指针形参,一般情况下由编译器通过寄存器自动传递(环境为===VS 2019版本),不需用客户传递
由调试以及反汇编代码可以清晰的观察到
该条指令则是获取的this形参指针存于ecx寄存器中
以成员变量_year赋值为例,编译器先从寄存器获取this指针后,在通过this指针对成员变量_year,进行赋值操作
(由此也可得出this的隐含指针形参特点,以及存储于寄存器,编译器由该指针对成员变量进行操作的特征)
补:并不是所有的this指针都是由寄存器自动传递的
成员函数: void TextFunction(...);
由push指令可知,该类this指针形参是通过参数压栈的方式传递的
那么如何该判断判断this指针是通过ecx寄存器传递还是通过参数压栈的方式进行传递的呢?
两者差别主要在于调用约定不同
SetDate()成员函数采用的__thiscall,TextFunc()成员函数则采用的是__cdecl
三、this指针面试题
1.this指针存在哪里?
如图Address()成员函数的栈帧,esp,ebp为分别标记栈顶和栈底的两个寄存器,在VS2019监视窗口中,通过引用&rthis地址实则就为&this地址,从范围大小,可清晰发现this指针存储于栈当中
2.this指针可以为空吗?
class Date
{
public :
void SetDate(int year,int month,int day)
{
_year = year;
_month = month;
_day = day;
}
void TextFunc()
{
cout << "Date::TextFunc()" << endl;
}
void Print()
{
cout << this << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.SetDate(2022, 4, 17);
d1.Print();
//this指针实则为当前对象(d1)的地址,用date局部变量接收
Date* date = &d1;
date = nullptr;
date->Print();
date->TextFunc();
return 0;
}
能完成编译!!!
但是发现经过下列一点变动
int main()
{
Date d1;
d1.SetDate(2022, 4, 17);
d1.Print();
//this指针实则为当前对象(d1)的地址,用date局部变量接收
Date* date = &d1;
date = nullptr;
date->Print();
date->TextFunc();
/
date->SetDate(2022, 6, 1);
return 0;
}
出现编译错误!!!
结论:成员函数由指针调用,则this指针(当前对象的地址)可能会为nullptr,但前提是不得对成员变量进行访问操作(成员变量有this指针形参访问),否则会出现编译错误