【C++】this指针

前言


  • 🚄 输入是学习的本质,输出是学习的手段。
  • 🔖 分享每一次的学习,期待你我都有收获。
  • 🎇 欢迎🔎关注👍点赞⭐️收藏✉评论,共同进步!
  • 🌊 “要足够优秀,才能接住上天给的惊喜和机会”
  • 💬 博主水平有限,如若有误,请多指正,万分感谢!

有这样一个人,它任劳任怨,它默默承受一切,帮我们打点好一切,但却不愿意将自己摆在明面上。
对在座的程序员们都无私奉献,甚至我们要将它堂堂正正地声明出来,都会拒绝我们(指报错)。

只愿意做各位老铁成功背后的’‘指针’‘,堪称现代版海螺姑娘,这个人就是——>this指针!!!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7wFu06Ec-1646461222031)(C:\Users\Z-zp\AppData\Roaming\Typora\typora-user-images\image-20220305141840745.png)]

this指针
class Data
{
public:

	void Init(Data* this, int year, int month, int day)
	{
		year = year;
		month = month;
		day = day;
	}

private:

	int year;
	int month;
	int day;
};

int main()
{
	Data d1;
	d1.Init(2022, 1, 1);

}

这段代码中,函数的形参名与成员变量的名字相同,当我们调试的时候,可以看到,成员变量的值并没有被改变。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jh5T8iHs-1646461222032)(C:\Users\Z-zp\AppData\Roaming\Typora\typora-user-images\image-20220129194027631.png)]

这是由于编译器并不能区分,你到底要的是成员变量还是形参,因此遵循就近原则,等号左右两端,都是形参。

如果我们要说明是形参赋值给成员变量,有三种方法。

  1. 声明作用域,告诉编译器,等号左端的变量是类成员变量。
class Data
{
public:

	void Init(int year, int month, int day)
	{
		Data::year = year;
		Data::month = month;
		Data::day = day;
	}

private:

	int year;
	int month;
	int day;
};

这种方法虽然能得到正确结果,但是麻烦,不实用。

  1. 修改成员变量名称或形参名称,这是最有效、方便避免产生歧义的方法。

我们可以养成自己的代码风格,比如在成员变量前后加上短横线"_",用来说明它是类的一部分,也能起到区分的作用。

class Data
{
public:

	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:

	int _year;
	int _month;
	int _day;
};
  1. 用this指针
class Data
{
public:

	void Init(int year, int month, int day)
	{
		year = year;
		month = month;
		day = day;
	}

private:

	int year;
	int month;
	int day;
};

int main()
{
	Data d1;
    Data d2
	d1.Init(2022, 1, 1);
	d2.Init(2022, 1, 2);
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UoI6ORvO-1646461222033)(C:\Users\Z-zp\AppData\Roaming\Typora\typora-user-images\image-20220129203240372.png)]

成员函数是存储在公共代码区中,那么两个对象在调用同一个函数的时候,不怕两次调用改变的是同一个对象而不是两个对象吗?怎么区分开来?

编译器在编译成员函数的时候,会增加一个隐含的参数——Data * this

this是C++中的关键字,只有一个作用,那就是作为成员函数的隐含参数

实际上编译时代码是这样的

class Data
{
public:

	void Init(Data* this, int year, int month, int day)  //隐含的this指针
	{
		year = year;
		month = month;
		day = day;
	}

private:

	int year;
	int month;
	int day;
};

int main()
{
	Data dt;
	d1.Init(&d1,2022, 1, 1);   //编译时自动添加地址
	d2.Init(&d2,2022, 1, 1);   //编译时自动添加地址
}

在对象调用函数时,编译器会隐含地将对象的地址也传给函数,并在函数中隐含地添加this指针用来接收

注意:这里一直在强调 “隐含地添加”
这里是为了方便展示,才明确地将d1的地址写在函数的调用里,将this指针写在形参中。

但实际上我们不能越俎代庖,不能自己在调用函数时传对象的地址,不能自己在函数形参中添加this指针

这是编译器去做的事,如果我们把它明确地写出来了,
编译就会报错。

但是我们可以使用this指针


我们可以利用this指针来说明等号左边的变量是对象的成员变量,即:

class Data
{
public:

	void Init(Data* this, int year, int month, int day)  //隐含的this指针
	{
		this->year = year;
		this->month = month;
		this->day = day;
	}

private:

	int year;
	int month;
	int day;
};

int main()
{
	Data dt;
	d1.Init(2022, 1, 1);   //编译时自动添加地址
	d2.Init(2022, 1, 1);   //编译时自动添加地址
}

通过取不同名称避免形参与类成员变量的名字相同时,编译器也是默认添加this指针的,只是它帮我们隐藏省去了。即,在调用函数时,都是通过this指针去访问成员变量的

class Data
{
public:

	void Init(Data* this, int year, int month, int day)  //隐含的this指针
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}

private:
    
	//名称不同
	int _year;
	int _month;
	int _day;
};

int main()
{
	Data dt;
	d1.Init(2022, 1, 1);   //编译时自动添加地址
	d2.Init(2022, 1, 1);   //编译时自动添加地址
}

总结:

this指针的特性

  1. this指针的类型:类类型* const

  2. 只能在“成员函数”的内部使用

  3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。

  4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2SMO35U-1646461222033)(C:\Users\Z-zp\AppData\Roaming\Typora\typora-user-images\image-20220129205949128.png)]

调用函数时取对象的地址,通过寄存器传递。


  • this指针存在哪里?

this指针虽然是个隐含的参数,但是毕竟也是属于函数的一部分,因此和函数一样,this指针也是存储在栈帧中的。

  • this指针可以为空吗?

可以

我们看这一段代码,会崩溃吗

class Data
{
public:

	void Print()
	{
		cout << "Print()" << endl;
	}


	void Year()
	{
		cout << "year = " << _year;
	}

private:

	int _year;
};

int main()
{
	Data* p = NULL;
	
	p->Print(); // 1.
    
	p->Year();	// 2.

}

这里可能会产生疑惑:

p是空指针,空指针怎么能解引用,所以程序全崩。

因为成员函数并不在类对象中,所以这里其实没有对指针p解引用,可以理解为是将p指针传递给成员函数,用this接收。


然后我们再来看这个代码的1和2:

函数中,this指针接收到的是空指针,函数是通过this指针访问成员变量的

  1. 调用Print函数后,我们没有访问类成员对象,因此不会对this指针解引用,所以程序运行正常.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EAiYVWQl-1646461222033)(C:\Users\Z-zp\AppData\Roaming\Typora\typora-user-images\image-20220129213520484.png)]

2.调用Year函数后,函数通过this指针访问_year,因此程序会崩。

void Year()
{
	cout << "year = " << this->_year;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿波呲der

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值