先上代码:
#include <iostream>
using namespace std;
#include <string>
class Person
{
public:
int weight;
Person(int weight)
{
//this指针指向 被调用的成员函数 所属的对象,即谁调用该函数,this指针指向谁
this->weight = weight;
}
Person Add(Person &p)
{
this->weight = this->weight + p.weight;
return *this;
}
};
int main()
{
Person p1(10);
Person p2(10);
p2.Add(p1).Add(p1).Add(p1);
cout << "p2的体重是:" << p2.weight << endl;
system("pause");
return 0;
}
写这段代码的目的是为了学习this指针。this指针可已返回对象本身。所以 p2.Add(p1).Add(p1).Add(p1); 语句可以实现p2体重加上多个p1体重的效果。
但是问题来了。
运行结果如下:
这结果不对啊,怎么就加了一个p1?这怎么会回事??为了查找问题,我试着在类方法Add上增加了一句来显示运行过程的语句。
Person Add(Person &p)
{
this->weight = this->weight + p.weight;
cout << "的weight是:" << this->weight << endl;
return *this;
}
之后运行结果如下:
???不对啊,都已经加到40了,怎么最后又变成20了??
嗯,好像发现哪里不对劲了。是不是产生了匿名对象??
于是为了验证猜想,将代码小改了一下,如下:
class Person
{
public:
int weight;
string name = "p3";
Person(int weight, string name)
{
//this指针指向 被调用的成员函数 所属的对象,即谁调用该函数,this指针指向谁
this->weight = weight;
this->name = name;
}
Person(const Person& p)
{
weight = p.weight;
}
Person Add(Person &p)
{
this->weight = this->weight + p.weight;
cout << this->name <<"的weight是:" << this->weight << endl;
return *this;
}
};
int main()
{
Person p1(10, "p1");
Person p2(10, "p2");
p2.Add(p1).Add(p1).Add(p1);
cout << "p2的体重是:" << p2.weight << endl;
system("pause");
return 0;
}
我在类中增加了一个属性name,给了他一个默认值p3,同时,重写了拷贝构造函数,拷贝函数中只拷贝属性weight。这样,当Add方法中的this->name打印出p3的时候就知道这是产生匿名对象了。
果然,出现了匿名对象:
这不对啊,怎么会出现匿名对象。。。。
哦,马虎了。类方法Add的返回值没加 & ,所以其返回值是一个Person对象。
首先,看第一部分p2.Add(p1),对象p2调用了Add方法,输入参数为p1对象,由于是p2直接调用,所以该步确实修改了p2的weight属性,变为20.
然后,在执行==p2.Add(p1)==后会又一个返回值,返回值为*this。在该步中,是p2调用的Add方法,所以this指针是指向p2的指针,*this就是p2对象本身。当一个方法进行值返回返回对象时,返回的并不是对象的本身,而是给对象的拷贝。想要验证的话很简单,在拷贝构造函数中添加一个输出:
Person(const Person& p)
{
weight = p.weight;
cout << "拷贝构造函数的调用" << endl;
}
运行结果如下:
可以看到,在输出p2的weight是:20后,调用了拷贝构造函数。所以其返回了一个匿名对象,这个匿名对象是p2的拷贝。
再然后,==p2.Add(p1).Add(p1)在此调用了Add方法,是p2.Add(p1)的返回值调用了Add方法,而p2.Add(p1)==的返回值是一个匿名类,所以其调用Add方法修改的是该匿名类中的属性,并不是p2的属性,所以p2的weight依旧是20。
==p2.Add(p1).Add(p1).Add(p1);与p2.Add(p1).Add(p1)==同理。
所以最后,p2的weight的值是20。
正确的写法应该是:
Person& Add(Person &p)
{
this->age = this->age + p.age;
cout << this->name <<"的age是:" << this->age << endl;
return *this;
}
运行结果如下:
Add方法的返回值应该是一个Person对象那个的引用。
这样 p2.Add(p1) 返回的就是p2的一个引用,相当于p2本身。所以p2.Add(p1).Add(p1) 中再次调用Add方法的就是p2,而不是匿名类。在运行结果中同样可以看出,因为整个运行过程中都没有调用拷贝构造方法。
引用虽然是个好东西,但是也要细心啊。