1 this指针
问题引入:
Date类中有Init与d1调⽤Init和
d1对象还是d2对象呢?
c
#include<iostream>
using namespace std;
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(2025, 11, 8);
d2.Init(2025, 11, 9);
d1.print();
d2.print();
return 0;
}

不同的对象本质就是它们的地址不同,那函数区分这两个对象也一定根据它们的地址进行区分。
可是我们也看到我们调用函数的时候并没有传入各对象的地址啊,其实这里就是C++的隐含的this指针来解决。
在编译器编译后 ,类的成员函数都会在形参的第一个位置增加一个当前类类型的指针,叫做
this指针。eg:void Init(int year, int month, int day)--被编译器替换为--void Init(Date* const this, int year, int month, int day)而我们调用成员函数时便是
eg:d1.print()--被编译器替换为--d1.print(&d1),我们在调用函数的时候就将当前对象的地址 传递给了this指针,从而来确定函数调用对象的。
在类的成员函数中访问成员变量本质也是通过this指针访问的
c
void Init(int year, int month, int day)
{
_year = year;//等价于this->_year = year;
_month = month;
_day = day;
}
小结:访问类的成员函数和成员变量都是通过
this指针确定对象的
2 this指针位置的限定
C++规定this指针不能在实参和形参的位置显示写 ,在形参和实参位置由编译器在编译时候处理 ,只有在成员函数内部可以显示运用this指针
在实参和形参的位置报错:


我们也可以这样想,编译器会固定帮你默认添加 ,你自己再显示添加在实参位置(函数调用参数太多 ),形参位置(函数调用参数太少)。
在成员函数内部:

我们看到可以正常使用
this指针内存区域说明:我们也看到this指针就是函数的参数 ,所以this指针是存在栈区 的,不过有时候编译器为了加快速度也会将其放入寄存器 之中这个汇编指令便是将
this指针变量所存储的值放入rax寄存器中。
3 this指针类型说明

我们可以看到this指针指向不能更改,但其指向的空间内容可以修改。所以this指针是一个指向被const修饰的指针,在Date类中就是Date * const this
两道判断题
接下来我们通过两道判断题进一步的理解this指针
1.下面程序编译运行结果是()
编译报错/运行崩溃/正常运行
c
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
p->Print();
return 0;
}

这段代码实际上被正确的执行了,接下来我们详细的分析下
在上面代码中其实最让人迷惑的就是p->Print(),这里好像是空指针的解引用啊,这难道不会运行崩溃嘛?
实际上面对p->Print()这个语句编译的时候做了两件事
- 找到
Print函数的出处(声明或者定义),调用一个函数被编译后在汇编指令上就是[call 函数地址] - 对象或者对象指针调用在编译处理后都传递
this指针
本题在
this指针(nullptr)的解引用,所以不会有任何的错误
但是如果在Print函数内部访问成员变量则会运行崩溃

小提醒:编译报错一般是语法出现了问题,对空指针解引用并不是语法层面的问题,在编译的时候编译器只知道这个是一个指针解引用符合语法,只有在运行的时候才知道这是个
nullptr才报错
1.下面程序编译运行结果是()
编译报错/运行崩溃/正常运行
c
#include<iostream>
using namespace std;
class A
{
public:
void Print()
{
cout << "A::Print()" << endl;
//cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p = nullptr;
(*p).Print();
return 0;
}

这个题目答案也是正常运行
p为nullptr,空指针的解引用并不会触发语法编译的问题,那只有在运行的时候才会报错。
可是在运行的时候编译器是按照你的代码逻辑转化为对应指令的而不是看到*p就一定有执行*p的指令,具体看代码实际表达的实际意义是什么。
在这个代码中*p的指令存在与否不会影响程序的实现,所以根本就没有*p的指令,所以代码正常运行


我们可以清楚的看到汇编指令上,在Print函数调用方面没有区别,更加证实了我们的说明
