一、this指针的引出
我们先来定义一个日期类 Date
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout <<_year<< "-" <<_month << "-"<< _day <<endl;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.Init(2022,1,11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
return 0;
}
对于上述类,有这样的一个问题: Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,从汇编代码上看:它们的调用地址都是一样的。
d1.Init(2022, 1, 11);
00007FF677B45ECD mov r9d,0Bh
00007FF677B45ED3 mov r8d,1
00007FF677B45ED9 mov edx,7E6h
00007FF677B45EDE lea rcx,[d1]
00007FF677B45EE2 call Date::Init (07FF677B4146Ah)
d2.Init(2022, 1, 12);
00007FF677B45EE7 mov r9d,0Ch
00007FF677B45EED mov r8d,1
00007FF677B45EF3 mov edx,7E6h
00007FF677B45EF8 lea rcx,[d2]
00007FF677B45EFC call Date::Init (07FF677B4146Ah)
d1.Print();
00007FF677B45F01 lea rcx,[d1]
00007FF677B45F05 call Date::Print (07FF677B4146Fh)
d2.Print();
00007FF677B45F0A lea rcx,[d2]
00007FF677B45F0E call Date::Print (07FF677B4146Fh)
输出结果:
2022-1-11
2022-1-12
那当d1调用 Init 函 数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
这是由于C++在这段代码中做出手脚 ,C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
在调用的时候也传的是各自的地址。这样就十分清晰明了了。这就是隐含的this指针

上面所注释的都是隐含的 this 指针 在操作。
注意:这里我们不能显示this指针所操作的写出来,因为他是隐含的,我们不能抢了编译器的活。但是我们可以直接在类里面用。
void Print()
{
cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}
二、this指针的特性
1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
class MyClass {
int value;
public:
void modifyThis() {
MyClass obj;
// this = &obj; // 错误!this 是常量指针,不能修改其指向的地址
this->value = 10; // 合法:可以修改成员变量
}
};
2. 只能在“成员函数”的内部使用
class MyClass {
int value;
public:
void validUse() {
this->value = 10; // 合法:非静态成员函数中使用
}
static void staticFunc() {
// this->value = 20; // 错误!静态函数中无 this 指针
}
};
void globalFunc() {
// this->value = 30; // 错误!全局函数中不能使用 this
}
3. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

4. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针。

三、练习this指针
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void Print()
{
cout << "Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}
结果:C 正常运行
原因:Print()函数是存在公共代码区中,编译的时候在公共代码区中找到这个函数,和普通的函数调用是一样的,只需要call函数地址就行。这里p是空指针,传过去的this指针只是接收了p的空指针,就类似于this指针被初始化为空指针。这是允许的。
再来一题:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
void PrintA()
{
cout<<_a<<endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->PrintA();
return 0;
}
结果:B 运行崩溃
原因:这里p是空指针,传过去的this指针只是接收了p的空指针,但是在PrintA()中,会隐含一个this->_a,而this指针是一个空指针,访问this指针_a的位置,就要对this指针进行解引用,此时程序就会崩溃,因为对空指针进行了解引用。
通过两题总结:
1.this指针是可以为空的
2.this指针存储在栈里

1054

被折叠的 条评论
为什么被折叠?



