this指针



前言

视频链接

关于成员变量和成员函数分开存储的文章




我们知道在C++中成员变量和成员函数是分开存储的

每一个非静态成员函数只会诞生一份函数实例,当我们实例化出多个对象后,这些同类型的对象会共用一块代码

那么问题是:这一块代码是如何区分那个对象调用自己的呢?通过this指针

c++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象,谁调用成员函数this指针就指向谁

this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,直接使用即可







1.this指针的用途:

  • 当形参和成员变量同名时,可用this指针来区分
  • 在类的非静态成员函数中返回对象本身,可使用return *this


示例1:当形参和成员变量同名时,可用this指针来区分

#include<iostream>
using namespace std;



class Person {
public:
	Person(int age) {
		age = age;

	}

	int age;


};

void test01() {

	Person p(25);
	cout << "p.age=" << p.age << endl;



}


int main() {

	test01();



	return 0;
}

在这里插入图片描述
可以看出,当形参与成员变量同名时,无法正常赋值
解决方法如下:

Person(int age) {
		age = age;

	}

改成:

Person(int age) {
		this->age = age;
	//也就是左边age前加个this->,代表这是成员变量
	//this指针指向被调用的成员函数所属的对象,谁调用成员函数this指针就指向谁

	}

在这里插入图片描述





示例2:在类的非静态成员函数中返回对象本身,可使用return *this

#include<iostream>
using namespace std;
#include<string>
class Person {
public:
	// 1.解决名称冲突
	Person(int age) {
		this->age = age;
	}
	int age;
	// 2.返回对象本身用*this
	// 修改后的函数如下
	// 必须要返回引用的方式Person&
	// 不能返回一个普通对象Person(这相当于返回值,如果返回值,return语句会拷贝构造出新的对象,就不是p2了)
	Person& PersonAddAge(Person& p) {
		this->age = this->age + p.age;
		// this指向p2的指针,而*this指向的就是p2这个对象本体
		// return*this返回的就是调用这个成员函数的对象

		cout << "如果函数返回的是引用,那么&(*this)=" << int(&(*this)) << endl<<endl;
	

		return *this;
	}
};
// 1.解决名称冲突
void test01() {
	Person p1(18);
	cout << "p1的年龄为:" << p1.age << endl;
	
	
}
// 2.返回对象本身用 *this
void test02() {
	Person p1(10);
	Person p2(10);

	// 使用一次PerosnADDAge函数,发现可以正常赋值
	//p2.PersonAddAge(p1);

	// 如果一次不够我想要多次使用呢?
	// p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);可不可以呢?
	// 答案是可以的,但是PersonADDAge得做修改
	// 上面体现了链式编程思想,cout就是这样子的
	cout << "&p2=" <<int(&p2) << endl;
	p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
	cout << "p2的年龄为:" << p2.age << endl;
}
int main() {
	//test01();
	test02();
	system("pause");
	return 0;
}

在这里插入图片描述




如果把

Person& PersonAddAge(Person& p) {
		this->age = this->age + p.age;
		// this指向p2的指针,而*this指向的就是p2这个对象本体
		// return*this返回的就是调用这个成员函数的对象

		cout << "如果函数返回的是引用,那么&(*this)=" << int(&(*this)) << endl<<endl;
	

		return *this;
	}

改成:

	Person PersonAddAge(Person& p) {
		this->age = this->age + p.age;
	
		cout << "如果函数返回的是值,那么&(*this)=" << int(&(*this)) << endl<<endl;
	

		return *this;
	}

在这里插入图片描述

我们发现:p2的年龄变为了20,而且调用PersonAddAge函数中只有第一次的*this一样( 这也就解释了为什么p2.age=20,因为 * this只指向了一次p2,p2对象的PersonAddAge函数其实只加了一次,后面加的两次已经变成新对象里的值了),所以此时this并不是指向p2了,return语句会拷贝构造出跟p2数据一样但地址不同的新对象



总结:
1.在类的非静态成员函数中返回对象本身,可使用return *this
2.但必须返回的是引用(Person&),不能返回的是一个值(Person)。
3.cout<<体现了链式编程思想,可以无限追加






2. const修饰成员函数以及this指针的本质

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
void showPerson() const
	{    // 特殊申明
		this->m_C = 100;// 不会报错
		this->m_B = 100;报错
		this->m_A = 100;报错
		// 本质上this指针是个指针常量,它的指向不可以修改,this以及指向一个对象了,不能再让它指向空,不过this指针指向的值可以改
		// const Person *const this,如果再加个const那么它指向的值也不可以改了
		// this = NULL;//this指针是指针常量,它的指向不可以更改,他已经指向一个对象了。
		cout << m_C << endl;

	}
int m_A;
int m_B;
mutable int m_C;//特殊变量,即使在常函数中,也可以修改这个值

在这里插入图片描述

常函数的本质:在成员函数后加const,修饰的是this指针的指向,让this指针指向的值也不可以改了




常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数
int m_A;
int m_B;
mutable int m_C;//特殊变量,即使在常函数中,也可以修改这个值



// 常函数
void showPerson() const
	{    // 特殊申明
		//this->m_C = 100;// 不会报错
		//this->m_B = 100;//报错
		//this->m_A = 100;//报错
		// 本质上this指针是个指针常量,它的指向不可以修改,所以this不能指向空,但this指针指向的值可以改
		// const Person *const this。this指针的指向和指向的值都不可以改
		// this = NULL;//不能改变this指针的指向,因为this指针是指针常量
		cout << m_C << endl;

	}

//  普通函数
	void func() {
		m_A = 45;
	}

// 常对象
void test02() {
	const Person p;// 在对象前加const,变为常对象
	p.m_A = 100;//不可修改,常对象可以访问成员变量,但是不能改变成员变量的值
	// 也就是说常对象访问的成员变量是个常量,除非这个成员变量在声明时加了关键字mutable
	p.m_C = 500;//可以修改,如果再成员变量前加个mutable,那么常对象就可更改这个成员变量的值
   p.showPerson();
	// 常对象只能调用常函数
	 //报错
	 p.func();
}

在这里插入图片描述

常对象的本质:在声明对象前加const称该对象为常对象,常对象也让this指针指向的值不可以改




完整代码:

#include<iostream>
using namespace std;
#include<string>
// const修饰成员函数
class Person {
public:

	Person(int a, int b, int c);



	// this指针的本质是 指针常量
	void showPerson() const
	{    // 特殊申明
		//this->m_C = 100;// 不会报错
		//this->m_B = 100;//报错
		//this->m_A = 100;//报错
		// 本质上this指针是个指针常量,它的指向不可以修改,所以this不能指向空,但this指针指向的值可以改
		// const Person *const this
		// this = NULL;
		cout << "m_A=" << m_A << "    " << endl
			<< "m_B=" << m_B << "    " << endl
			<< "m_C=" << m_C << "    " << endl;

	}
	void func() {
		cout << "this func()" << endl;
	}
	int m_A;
	int m_B;
	mutable int m_C;//特殊变量,即使在常函数中,也可以修改这个值
};

Person::Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}

//普通对象
void test01() {
	Person p(22,23,56);
	cout << "普通对象p信息如下:" << endl;
	p.showPerson(); cout << endl;
	p.m_A = 52; p.m_B = 32; p.m_C=65;
	cout << "普通对象p信息修改后:" << endl;
	p.showPerson(); cout << endl;
}
// 常对象
void test02() {
	const Person p1(66,77,89);// 在对象前加const,变为常对象。常对象和普通对象一样初始化

	p1.m_A; p1.m_B;//不可修改
	cout << "常对象p1信息如下:" << endl;
	p1.showPerson(); cout << endl;

	p1.m_C = 500;//可以修改

	cout << "将常对象p1信息修改后:" << endl;


   p1.showPerson();
	// 常对象只能调用常函数
	 //报错
   //p.func();
 

}
int main() {
	test01();
	test02();
	system("pause");
	return 0;

}

在这里插入图片描述



常函数和常对象总结

总结:常函数

  • 成员函数后加const后我们称为这个函数为常函数
    void showPerson() const{},此时this指针由Person * const this变成const Person * const this,无法修改this指针指向的值
  • 常函数内不可以修改成员属性
  • 成员属性声明时加关键字mutable后,在常函数中依然可以修改
    mutable int m_C;
    常函数的本质:在成员函数后加const,修饰的是this指针的指向,让this指针指向的值也不可以改了

总结:常对象

  • 声明对象前加const称该对象为常对象
    const Person p1
  • 常对象只能调用常函数
  • 常对象和普通对象那样正常赋值,不过常对象里的成员变量是常量,不可修改。除非这个成员变量声明时加了关键字mutable(注意成员函数前面不可以加关键字mutable,常对象要想调用成员函数,必须把它变为常函数

总结:this指针
this指针的本质:指针常量。指针的指向不可以改,指针指向的值可以改。
this指针本质代码表示:类名 * const this=&实例化对象名;
再加个const变成const 类名 *const this=&实例化对象名,这样它指向的值也不可以改了。

怎么把前面这个const加进去,使this指针指向的值也不可以改呢?
只需把成员函数变为常函数或者创建常对象,即void showPerson()变为void showPerson() const{}后或者创建常对象const Person p,编译器会将this指针由Person * const this变成const Person * const this,此时就无法修改this指针指向的值






3. 空指针访问成员函数(this指针的一个坑)

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

如果用到this指针,需要加以判断保证代码的健壮性



示例1:运行下面代码,看看有无错误

#include<iostream>
using namespace std;
#include<string>
// 空指针调用成员函数
class Person {
public:
	void showClassName() {
		cout << "this is Person class" << endl;
	}
	/*void showPersonAge() {
		// m_age是个属性,在属性前面都默认加了个this->
		// 报错原因是因为传入的指针是个NULL
	cout << "age=" << m_age//其实完整的是this->m_age
			<< endl;
	}
	int m_age;*/
};
	void test01() {
		Person* p = NULL;//创建一个空指针
		p->showClassName();
		//p->showPersonAge();
	}
	int main() {
		test01();
		system("pause");
		return 0;
	}

正常运行
在这里插入图片描述




示例2:

#include<iostream>
using namespace std;
#include<string>
// 空指针调用成员函数
class Person {
public:
	void showClassName() {
		cout << "this is Person class" << endl;
	}
	void showPersonAge() {
		// m_age是个属性,在属性前面都默认加了个this->
		// 报错原因是因为传入的指针是个NULL
	cout << "age=" << m_age//其实完整的是this->m_age
			<< endl;
	}
	int m_age;
};
	void test01() {
		Person* p = NULL;//创建一个空指针
		p->showClassName();
		p->showPersonAge();
	}
	int main() {
		test01();
		system("pause");
		return 0;
	}

报错,原因是我们创建的对象指向空,this指针是个空指针。
空指针怎么能访问类里面的属性呢
在这里插入图片描述



空指针是不能访问到类里面的属性的,我们的改进措施也仅仅是让程序不崩而已,无法做到让个空指针打印出类里的属性出来
解决方法如下:

void showPersonAge() {
		// m_age是个属性,在属性前面都默认加了个this->
		// 报错原因是因为传入的指针是个NULL
	cout << "age=" << m_age//其实完整的是this->m_age
			<< endl;
	}
	int m_age;
};

改成:

void showPersonAge() {
		// m_age是个属性,在属性前面都默认加了个this->
		// 报错原因是因为传入的指针是个NULL
		//  解决方案
		     if(this == NULL)
			 {
			 return;
			 }
		
		// 如果this为空指针,下面的代码就不会执行了
		// 程序也就不会崩溃了
		cout << "age=" << m_age//其实完整的是this->m_age
			<< endl;
	}
	int m_age;
};


判断代码:

 if(this == NULL)
			 {
			 return;
			 }


总结:
1.C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针
2.如果用到this指针,需要加以判断保证代码的健壮性
3.空指针的作用仅仅就是调用一下成员函数而已,他无法访问成员属性(更不可能赋值)所以如果在成员函数中用到了空的this指针,必须加判断代码。
4.空指针平常基本用不到,不要实例化个空指针出来





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值