C++隐藏的this指针(详解)

1 this指针

问题引入:Date类中有InitPrint两个成员函数,函数体中没有关于不同对象的区分,那当d1调⽤Init
Print函数时,该函数是如何知道应该访问的是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指针

本题在Print函数内部没有对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;
}

这个题目答案也是正常运行
pnullptr,空指针的解引用并不会触发语法编译的问题,那只有在运行的时候才会报错。

可是在运行的时候编译器是按照你的代码逻辑转化为对应指令的而不是看到*p就一定有执行*p的指令,具体看代码实际表达的实际意义是什么。

在这个代码中*p的指令存在与否不会影响程序的实现,所以根本就没有*p的指令,所以代码正常运行

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

相关推荐
虾..2 小时前
C++ 哈希
开发语言·c++·哈希算法
liu****2 小时前
14.日志封装和线程池封装
linux·开发语言·c++
将编程培养成爱好2 小时前
C++ 设计模式《统计辅助功能》
开发语言·c++·设计模式·访问者模式
一匹电信狗3 小时前
【C++】封装红黑树实现map和set容器(详解)
服务器·c++·算法·leetcode·小程序·stl·visual studio
wxin_VXbishe5 小时前
springboot在线课堂教学辅助系统-计算机毕业设计源码07741
java·c++·spring boot·python·spring·django·php
夕泠爱吃糖5 小时前
template关键字
开发语言·c++·template
mit6.8245 小时前
[Avoid-MPC] AvoidanceStateMachine | `Step`心跳函数 | Callback设计
c++
ceclar1235 小时前
C++文件操作
开发语言·c++
CSDN_RTKLIB6 小时前
【动态链接库】一、VS下基本制作与使用
c++