this指针的概念:
在C++中成员变量和成员函数是分开存储的。
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码。
那么问题是:这一块代码是如何区分哪个对象调用自己的呢?
c++通过提供特殊的对象指针,this指针,解决上述问题。
关键:this指针 指向 被调用的成员函数所属的 对象! 谁调用了成员函数,this就指向谁!
this指针是隐含在每一个 非静态成员函数 内的一种指针(内置的,我一直都在你身体里哦~)。
this指针不需要定义,直接使用即可。
this指针的用途:
- 当形参和成员变量同名时,可用this指针来区分;
- 在类的非静态成员函数中返回对象本身,可使用return *this。
问题描述
this指针主要用于解决两个问题:
1、解决名称冲突
2、返回对象本身用*this
现在我们创建一个类:
class Person
{
public:
Person(int age)
{
//1、当形参和成员变量同名时,可用this指针来区分
// age = age; // 这样cout输出的是30190,都是age,相当于有参构造函数没有给成员变量赋值
this->age = age; //点击右值的age会发现它和形参有阴影,点击左值的age会发现它和成员变量以及调用处的age有阴影
//this指针指向 被调用的成员函数 所属的 对象
}
void PersonAddAge(Person &p){
this->age += p.age;
}
Person& PersonAddPerson(Person p)
{
this->age += p.age;
//this指向p2的指针,而*this指向的就是 p2本身
return *this; //得用Person&
}
Person PersonAddPerson2(Person p)
{
this->age += p.age;
//this指向p2的指针,而*this指向的就是 p2本身
return *this; //不加&
}
int age;
};
这个类里面有构造函数Person
、非静态成员函数PersonAddAge
、PersonAddPerson
、PersonAddPerson2
以及非静态成员变量int age
。
详细解释:
1、解决名称冲突:
void test01()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
}
main函数调用test01时,如果采用age=age的方式在构造函数中赋值,会出现输出一个随机数的错误,比如输出30190,而非10。主要原因还是在于形参和成员变量同名,相当于没有赋值操作。把构造函数里的东西都注释了会发现也是输出一个随机的数字。因此需要用this指针的方式解决名称冲突。
2、返回对象本身用*this:
第一种情况:不加return返回值
void test02()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
Person p2(10);
p2.PersonAddAge(p1); //成员函数PersonAddAge属于p2,所以里面的this指针指向p2,计算结果就是p2的age加上p1的age
cout << "p2.age = " << p2.age << endl;
//error: invalid use of ‘void’,所以p2.PersonAddAge(p1)必须返回p2这个对象它才能继续 .
// p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
// cout << "p2.age = " << p2.age << endl;
}
可以对p2本身修改,输出:
p1.age = 10
p2.age = 20
但是如果p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
这样累加就会报错:
error: invalid use of ‘void’
所以p2.PersonAddAge(p1)必须返回p2这个对象它才能继续 .
第二种情况:加return返回值,返回Person & (引用返回)
void test02()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
Person p2(10);
p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);
cout << "p2.age = " << p2.age << endl;
}
调用PersonAddPerson
进行累加,输出:
p1.age = 10
p2.age = 40 (加了三次10,都是对p2这个对象进行操作的)
那么为什么Person要加&呢?
因为引用指向本身的内存
,不加引用相当于拷贝了(拷贝构造函数),而拷贝指向另一个内存。
请看下面的例子:
第三种情况:加return返回值,返回Person (值返回)
void test02()
{
Person p1(10);
cout << "p1.age = " << p1.age << endl;
Person p2(10);
Person p3 = p2.PersonAddPerson2(p1).PersonAddPerson2(p1).PersonAddPerson2(p1);
cout << "p2.age = " << p2.age << endl;
cout << "p3.age = " << p3.age << endl;
}
调用PersonAddPerson2
进行累加,输出:
p1.age = 10
p2.age = 20
p3.age = 40
分析:执行p2.PersonAddPerson2(p1)
会返回一个新的对象 p‘ ,它的age值是20,p2的age值由于this指针所以也是20,然后继续执行.PersonAddPerson2(p1)
,就会又创建一个新的对象 p’’ ,它的age值是30,而p2的age值依然是20,因为后面的操作和p2没关系了,依次类推把最后的结果赋值给p3,p3age值为40。
因此要注意区分 引用返回 和 值返回 的区别。
值得注意的是,请不要把 值传递方式返回
和 值方式返回局部对象
混淆了。
值方式返回局部对象这个链接里有关于它的描述,使用linux系统时会有一个RVO机制,它会少一次拷贝构造和析构的开销(编译器帮助我们作了优化)。