一. this指针的引出
首先我们来看以下代码:
#include <iostream>
using namespace std ;
class Data{
public :
void disPlay()
{
cout << _year << " - " << _month << " - " << _days << endl;
}
void setDays(int year,int month ,int day)
{
_year = year ;
_month = month ;
_days = day ;
}
private :
int _year ;
int _month;
int _days ;
};
int main()
{
Data d1 ;
Data d2 ;
d1.setDays(2021 , 10 ,10) ;
d2.setDays(2021, 10 , 20) ;
d1.disPlay() ;
d2.disPlay() ;
}
对于上述类,有这样的一个问题: Date类中有SetDate与Display两个成员函数,函数体中没有关于不同对象的区分------------函数体都是放在公共代码区,那当d1调用SetDate函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢? 所以C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。 还有此处并不是给类成员变量赋值,而是给对象的成员变量赋值, 所以编译器才在作用域内加this指针,用this指针解引用访问对象的成员变量。
上述术语转换成代码 :
void disPlay(Date* this)
{
cout << this._year << " - " << this._month << " - " << this._days << endl;
}
void setDays(Data* this,int year,int month ,int day)
{
this._year = year ;
this._month = month ;
this._days = day ;
}
强调一点题外话,类里面的成员变量只是声明, 并没有为它们开辟空间。 容易令人无解的是, C++ 11 当中为无参构造函数打啦补丁, 会给类成员赋初值,但此初值并非我们所想的初值,而是缺省值,故这并不能代表是定义类中的成员变量。 当程序员调用无参构造函数时,默认的构造函数并不会给类成员变量赋初始值,如果有这些缺省值,就使用这些缺省值初始化,当然以上讨论的是基本类型, 若是自定义类型,编译器会调用自定义类型的无参构造函数来为自定义类型初始化。
二 . this指针的特性
- this指针的类型:类类型* const
- 只能在“成员函数”的内部使用
- this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。
- this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。(大家可以通过反汇编的方法来进行验证)
三. 关于this指针的相关问题
this指针可以为空吗?带着这个问题考虑一下代码。
class A
{
public:
void Show()
{
cout<<"Show()"<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Show();
}
很奇怪,程序并没有报错,反而正确的运行啦,why? 在解释这个结果之前我们要知道类中的成员函数并不是存储在对象当中,而是存储在公共代码区。 当p指针调用Show()函数时, 并不会去访问p指向的空间,不存在空指针解引用,这里只会把p传递给隐含的this指针,但是Show函数中也没有解引用this指针,只是简单的打印Show这个字符串。故程序正常运行。
若将代码改写一下。
#include <iostream>
using namespace std;
class A
{
public:
void PrintA()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
}
注意报错的地方, 该行代码显式的写应该是这样c cout << this._a << endl; 程序错误的导致空指针解引用,报错啦。 两段代码的区别显而易见。 总结, this指针是可以为空, 但要视情况而定。
|