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

1 this指针

问题引入:Date类中有Init与Print两个成员函数,函数体中没有关于不同对象的区分,那当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;
}

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

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

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

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

相关推荐
YYYing.6 小时前
【设计模式系列 (七) 】桥接模式
c++·后端·设计模式·桥接模式
高山有多高7 小时前
【Linux笔记】Linux自定义Shell
linux·c++
悠仁さん8 小时前
【C++】vector 类
开发语言·c++
_upupup8 小时前
智能指针的原理及简单模拟实现(C++)
开发语言·c++
l1t8 小时前
DeepSeek总结的OpenZL压缩变换器
c++·算法
郝学胜-神的一滴8 小时前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建
坤坤子吖8 小时前
算法学习——高精度加减乘除
c++·笔记·学习·算法
朝朝辞暮i8 小时前
C++ 第 14 课:引用 &
开发语言·c++·算法
白山编程大哥9 小时前
适合初学者练习的 C/C++ 开源项目推荐
c语言·c++·开源
C++ 老炮儿的技术栈9 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c