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函数调用方面没有区别,更加证实了我们的说明

相关推荐
朔北之忘 Clancy6 分钟前
2020 年 6 月青少年软编等考 C 语言二级真题解析
c语言·开发语言·c++·学习·青少年编程·题解·尺取法
消失的旧时光-194312 分钟前
C++ 中的 auto 与 nullptr:不是语法糖,而是类型系统升级
开发语言·c++
fpcc24 分钟前
跟我学C++中级篇—C++17中的元编程逻辑操作
c++·模板编程
HABuo24 分钟前
【Linux进程(五)】进程地址空间深入剖析-->虚拟地址、物理地址、逻辑地址的区分
linux·运维·服务器·c语言·c++·后端·centos
AuroraWanderll44 分钟前
类和对象(六)--友元、内部类与再次理解类和对象
c语言·数据结构·c++·算法·stl
Tim_101 小时前
【C++入门】05、复合类型-数组
开发语言·c++·算法
jikiecui1 小时前
信奥崔老师:三目运算 (Ternary Operator)
数据结构·c++·算法
无限进步_1 小时前
【C语言&数据结构】另一棵树的子树:递归思维的双重奏
c语言·开发语言·数据结构·c++·算法·github·visual studio
汉克老师1 小时前
GESP2025年9月认证C++一级真题与解析(判断题1-10)
c++·数据类型·累加器·循环结构·gesp一级·gesp1级
不爱吃糖的程序媛1 小时前
OpenHarmony跨端生态适配全指南|Flutter/RN/三方库/C/C++/仓颉 鸿蒙化最佳实践
c语言·c++·flutter