C++中的this指针

对象内存分配方案

我们在前面C/C++区别最后提出,如果我们创建三个对象分别为c1,c2,c3
在这里插入图片描述
当我们对c1、c2、c3如果都进行完全独立的安排内存方案,如下:
在这里插入图片描述

这样分配全套的空间会使得当对象数量较多,内存会被消耗殆尽

所以我们使用的方案为,各对象的代码区公用:

此处c1,c2,c3我们只给它分配数据区,代码区被所有对象共享,继而出现一个重要的问题:既然对象只有属性而没有方法,当我们c1去调用方法时,方法如何去辨别处理的是c1对象的成员,所以我们引入了this指针的概念

编译器对类型的编译

编译器针对程序员自己设计的类型分三次编译

  • 第一:识别和记录类体中属性的名称,类型和访问限定,与属性在类体中的位置无关(如class CGoods 中的 Name,Amount,Price,Total_value)
  • 第二:识别和记录类体中函数原型(返回类型+函数名+参数列表),形参的默认值,访问限定,不识别函数体
  • 第三:改写在类定义中函数的参数列表和函数体,改写对象调用成员函数的形式

识别数据成员

对类的数据(属性)成员记录在案

private:
	char Name[21];
	int Amount;
	float Price;
	float Total_value;

识别函数声明

对类中函数的声明进行记录在案,仅识别函数声明,不识别函数体,对函数原型的识别

public:
	void RegisterGoods(const char* name, int amount, float price); //输入数据
	void CountTotal(void);			      //计算商品总价值
	void GetName(char[]);				  //读取商品名
	int GetAmount(void);				  //读取商品数量
	float GetPrice(void);				  //读取商品单价
	float GetTotal_value(void);	   		  //读取商品总价值

函数改写

void CGoods::RegisterGoods(CGoods * const this,const char* name, int amount, float price);
//void RegisterGoods(const char* name, int amount, float price);

我们在这里添加了 CGoods * const this 指针,在对函数体编译时,如果函数体中的标识符与属性名称一样,就会在前面加一个this指针

void CGoods::RegisterGoods(const char *name, int amount, float price)
{
	strcpy_s(Name,21, name);
	Amount = amount;
	Price = price;
}

修改后

void CGoods::RegisterGoods(CGoods * const this, const char *name, int amount, float price)
{
	strcpy_s(this->Name,21, name);
	this->Amount = amount;
	this->Price = price;
}
  1. 每一个类的成员函数都要加上this指针
  2. 在识别函数体时候遇到与类属性名称一样的标识符时在前面加上this指针

且当我们在定义对象时,调用成员函数的时候会进行改写,会将我们当前对象的地址给予this指针,继而当我们操作函数是就会对相应的对象属性进行操作

CGoods c1, c2, c3;
	c1.RegisterGoods("c++", 12, 98.99);
	//c1.RegisterGoods(&c1,"c++", 12, 98.99);
	c1.CountTotal();
	//c1.CountTotal(&c1);
	
	c2.RegisterGoods("java", 23, 12.23);
	//c2.RegisterGoods(&c2,"java", 23, 12.23);
	c2.CountTotal();
	//c2.CountTotal(&c2);
	
	c3.RegisterGoods("tea", 23, 34);
	c3.CountTotal();

在这里插入图片描述
当我们调用c1的成员方法时,this指针的值就是c1的地址,而去调用c2方法时,this指针指向c2的地址;并且this指针并不在对象里,而在类的成员函数里

其他关于this指针的问题

  1. 在我们改写时,实际上是CGoods * const this,这样会约束this指针不能进行改变,使得this指针失去作用

  2. this指针存在于成员方法,而不是存在于对象属性,只有调用成员函数才会有this指针

  3. 当我们在成员函数后面加上const,float GetTotal_value(void) const,const 在返回类型之前,代表放回的数值为常量,若是在方法之后代表我们的方法是一个常方法,也就是我们只能对对象的属性进行读取,而不能将对象的属性进行修改

float GetTotal_value(void) const
{
	int x = this->Amount;
	//this->Amount = 1000;  错误!!! 不能进行改写
}

这里也会进行一次改写

原本我们对float GetTotal_value(void)的改写为float GetTotal_value(CGoods * const this)
而我们将const写在函数后面float GetTotal_value(void) const,改写后的内容为float GetTotal_value(const CGoods * const this)

const修饰*this,也就是它的指向能力,this指针指向为常性,继而不能对类的属性进行修改

  1. 如果我们在定义对象时,我们对下面两种代码的成员方法重写如下:
    在这里插入图片描述
class CGoods
{
private:
	char Name[21];
	int Amount;
	float Price;
	float Total_value;
public:
	float GetPrice()				   //读取商品单价
	{
		return this->Price;
	}
	float GetTotal_value() const	   //读取商品总价值
	{
		return Total_value;
	}
};

void main()
{
	CGoods c1 = {"c++",12,23};
	const CGoods c2 = {"java",12,23};
	
	c1.GetPrice();
	c2.GetPrice(); //错误!!!
	c1.GetTotal_value();
	c2.GetTotal_value();
}

我们来研究为什么c1.GetPrice();是正确的,而c2.GetPrice();是错误的;

这是因为我们使用const修饰过 c2 后,使得不允许对 c2 属性进行修改,继而当我们在调用GetPrice()时候,使用普通指针指向c2会致使this指针能力扩展,所以是错误的,也就是说我们的常对象只能调用常方法,而普通对象既可以调用普通方法也可以调用常方法

  1. this指针的传递,通过thiscall的函数调用约定;this指针存放于ECX寄存器,参数从右到左压;当我们进行c1.RegisterGoods("c++",12,23); c1的地址通过ecx进行传递,到达函数内部时将ecx的值交给 this
    在这里插入图片描述
    在这里插入图片描述
    假如我们通过添加_cdecl关键字,使用c的调用约定
    在这里插入图片描述
    在这里插入图片描述
    则会直接将地址入栈push传入给参数,与其他参数是一样的,而默认C++的调用约定thiscall并没有push这一过程
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值