首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C++】一篇带你了解C++中隐藏的this指针

【C++】一篇带你了解C++中隐藏的this指针

作者头像
小陈又菜
发布2025-12-23 16:36:56
发布2025-12-23 16:36:56
280
举报

小伙伴大家好,今天我们将在这篇文章中讨论一个有趣的知识点--隐藏的this指针。本篇需要用到前面学的C++类和对象(上)的基础,如果大家还不太了解类和对象的基本思想,可以去回顾一下这篇文章【C++】带你一篇了解什么是OPP(面向对象编程),什么是封装?类和对象(上)

1. this指针的引出

接下来我们学习一个时间类,顾名思义,就是会输出我们输入的时间,我们先看一下这段代码:

代码语言:javascript
复制
class Date
{
public:
	void Display()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;
	d1.SetDate(2025, 7, 15);
	d2.SetDate(2025, 7, 16);
	d1.Display();
	d2.Display();
	return 0;
}

运行结果:

我们通过汇编代码来看一下两次调用的函数是不是同一个(我们之前讲过类对象的储存方式:只储存成员变量,成员函数放在公共代码段)

我们看到两次调用的函数的地址是一样的,那么大家思考一下,既然调用的函数是一样的,那么编译器为什么知道d1是2025-7-15。而d2是2025-7-16呢?

这是因为C++在处理这种情况的时候偷偷地做了手脚,添加了一个this指针,在这里就是Display()函数传入了一个this形参。

事实上,C++会为所有非静态的成员函数增加了一个隐藏的this指针,这个指针用来指向调用当前函数的对象,而对于类中所有成员变量和成员函数的访问,都是通过这个this指针。只不过这些操作对于用户来说是隐藏的,由编译器自动完成

我们将代码补全来解释可能会清晰一点(注意:代码补全是为了方便理解,不一定满足语法规则):

这样理解是不是就会好一些,也就是在调用成员函数时候都会往里面传入了一个指针,指向的是当前对象。但是再次提醒,我们不能显式地写出来,不能抢了编译器的活。


2. this指针的特性

在真正的编译器中,this使用const修饰的,也就是说

\left [ 1 \right ]
\left [ 1 \right ]

this本身是无法被修改的,但是它的内容可以被修改,

\left [ 2 \right ]
\left [ 2 \right ]

并且我们是可以直接使用的:

代码语言:javascript
复制
void Display()
{
	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

我们可以来打印一下this指针,还有d1、d2:

代码语言:javascript
复制
class Date
{
public:
	void Display()
	{
        //使用this指针
		cout << this << endl;
		cout << _year << "-" << _month << "-" << _day << endl;
	}	
 
	void SetDate(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;
	cout <<"d1:"<< & d1 << endl;
	cout <<"d2:"<< & d2 << endl;
 
	d1.SetDate(2025, 7, 15);
	d2.SetDate(2025, 7, 16);
 
	d1.Display();
	d2.Display();
	return 0;
}

运行结果:

并且我们刚才讨论过了,这个this指针是真实存在的,所以我们是可以直接使用的,当然我并不需要显示地传入参数,直接直接调用即可:

代码语言:javascript
复制
void Display()
{
	cout << this << endl;
	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

然后我们来讨论一下this指针的不可修改性,我们看下这段代码能不能编译成功:

代码语言:javascript
复制
void SetDate(int year, int month, int day)
{
	this = nullptr;    //将nullptr赋值给this
	_year = year;
	_month = month;
	_day = day;
}

很显然是错误的,因为前面提到了this是被const修饰的,是不允许被修改的。如果编译的话会爆出这样一个错误:

总结:

  • this类型:类类型* const
  • this指针本质上是一个成员函数的形参,是对象在调用成员函数的时候将对象的地址作为实参传毒给this形参,所以对象本身并不储存this指针
  • this只能在成员函数内部使用
  • this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

3. 练习一下

(1)下面的程序的运行结果是? A.编译报错 B.运行崩溃 C.正常运行

代码语言:javascript
复制
class A
{
public:
	void Show()
	{
		cout << "show()" << endl;
	}
private:
	int _a;
};
 
int main()
{
	A* p = nullptr;
	p->Show();
 
	return 0;
}

答案:C

因为之前在讲解类和对象的时候我们讲过,成员函数是储存在公共代码区,调用的时候只需要call函数的地址就行。而虽然我们这里this被赋值了nullptr,也就是this被初始化为空指针而已,只是被允许的,我们看一下运行结果和反汇编结果:

(2)下面的程序的运行结果是? A.编译报错 B.运行崩溃 C.正常运行

代码语言:javascript
复制
class B
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
 
	B* p2 = nullptr;
	p2->PrintA();
 
	return 0;
}

答案:B

大家可能有疑问,这不是跟上面一个类型的题目吗,为什么上面那个能够正常运行,这个就会运行崩溃呢?大家注意这两道题的区别,第二道题中存在对成员变量的访问(即this->_a),而成员变量的访问是需要获取对象的地址的(也就是this指针),但是这里的this指针被初始化成了空指针(因为p2被赋值了nullptr),所以这里就变成了对空指针的解引用,自然会报错:

(3)this指针是存在哪里的?A.栈 B.堆 C.静态区 D.常量区

答案:A

解释:

this指针是个形参,形参是在函数的栈桢里,在函数的栈桢里面的变量是属于栈中的。

有时候编译器会使用寄存器对其进行优化,将this指针存放在寄存器中:

下面这图可以更直观的看出涉及的变量的储存位置:


(本篇完)

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-12-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. this指针的引出
  • 2. this指针的特性
  • 3. 练习一下
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档