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

目录

1. this指针的引出

2. this指针的特性

3. 练习一下


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

1. this指针的引出

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

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 ]this本身是无法被修改的,但是它的内容可以被修改,\left [ 2 \right ]并且我们是可以直接使用的

void Display()
{
	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

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

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指针是真实存在的,所以我们是可以直接使用的,当然我并不需要显示地传入参数,直接直接调用即可:

void Display()
{
	cout << this << endl;
	cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

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

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.正常运行

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.正常运行

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指针存放在寄存器中:

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


(本篇完) 

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值