从 setter 方法返回 *this 时,对象变得不可变

Object becomes immutable when returning *this from a setter method

提问人:Ajay kumar soni 提问时间:8/6/2021 最后编辑:einpoklumAjay kumar soni 更新时间:8/6/2021 访问量:105

问:

我正在了解这个指针,它包含调用该函数的当前对象的地址。但是当我从成员函数返回当前对象时,我对这个指针有疑问。

#include<bits/stdc++.h>
using namespace std;
class Point
{
    private:
        int x,y;
    public:
        Point(int x,int y)
        {
            this->x = x;
            this->y = y;
            //cout<<this<<endl;                 
        }
        Point setX(int x)
        {
            this->x = x;
            //cout<<this<<endl;
            return *this;
        }
        
        Point setY(int y)
        {
            this->y = y;
            //cout<<this<<endl;
            return *this;
        }
        int getX()
        {
            return x;
        }                    
        int getY()
        {
            return y;
        }
};                                                           
int main()
{
    Point p(10,20);
    cout<<p.getX()<<" "<<p.getY()<<endl;
    p.setX(1000).setY(2000);
    cout<<p.getX()<<" "<<p.getY();
    return 0;
}

为什么 p.setX(1000).setY(2000) 只修改 x 的值,而不是 y? 为什么在第二个 cout 语句答案是 1000 20,但它应该是 1000 2000?

C++ 指向 这个

评论

3赞 Nathan Pierson 8/6/2021
setX并按值返回其点,而不是引用返回。这意味着,当您 时,您将返回要调用该方法的对象的副本。setYreturn *this
0赞 paddy 8/6/2021
是按值返回对象,而不是按引用返回对象。 包含 的副本。返回类型应为“如果要链接操作”。Point*thisPoint&
0赞 Jeremy Friesner 8/6/2021
请注意,通常 setter 方法 like 和根本不返回任何内容,即它们的返回类型通常为 .让他们返回 a 是合法的 C++,但这会让人们感到困惑。setX(int)setY(int)voidPoint
0赞 einpoklum 8/6/2021
@JeremyFriesner:这两种风格的二传手都很常见(坦率地说,我都不喜欢)。
0赞 paddy 8/6/2021
我想说的是,对于像 2D 点这样无处不在且简单的东西,用 getter 和 setter 将其包装在私有数据中似乎有点过分了。为什么不直接公开成员并完成它呢?

答:

1赞 songyuanyao 8/6/2021 #1

因为 (and ) 返回 by-value。在 中,返回一个临时的(复制自 ),在其上调用,任何修改都与 无关。setXsetYp.setX(1000).setY(2000);p.setX(1000)Point*thissetYsetYp

将它们更改为按引用传递。

Point& setX(int x)
//   ^
{
    this->x = x;
    //cout<<this<<endl;
    return *this;
}
    
Point& setY(int y)
//   ^
{
    this->y = y;
    //cout<<this<<endl;
    return *this;
}

评论

0赞 Ajay kumar soni 8/6/2021
所以你是说 p.setX(1000) 正在对其从 *this 复制的对象进行更改。既然它正在更改其本地对象副本中的值,那么为什么更改会反映回 p.x 值中。
0赞 songyuanyao 8/6/2021
@Ajaykumarsoni 不,我是说. changed ,则返回一个副本,然后对 copy 进行调用,对 copy 进行更改。副本将立即销毁,仅保留更改。setYp.setX(1000)p.xsetY(2000)yp.x
0赞 Ajay kumar soni 8/6/2021
好的,现在我明白了。由于我返回的是 Point 类型,因此 (*this) 将创建一个本地 Point 对象并返回它,然后在此本地对象上调用 setY(2000)。在这个本地返回的对象上,y 值将被更改。最初,我以为既然我从 setX 返回 (*this),那么 setX 将从中返回当前调用对象 (p)。然后它将在同一个对象上调用 setY。但相反,setX 将创建一个本地对象,然后它将返回。如果我在某个地方错了,请纠正我?
0赞 songyuanyao 8/6/2021
@Ajaykumarsoni 你是对的。这就是为什么更改为按引用返回可以解决此问题的原因;它使返回当前对象而不是副本。setX
3赞 einpoklum 8/6/2021 #2

原因是 your 和 methods 返回一个 - 它们返回对象的副本。因此,您设置的是点的临时副本的成员,而不是原始点的成员。setX()setY()PointsetY()y

您可以通过将签名从以下位置更改为以下位置来纠正此问题:

Point setX(int x)

自:

Point& setX(int x)

同样,对于 .您会注意到返回类型现在是 - 对对象的引用。setY()Point&Point

但是请注意,类的 getter 和 setter 方法有效地允许处理和喜欢公共对象。因此,除非你打算用坐标的一些隐式表示来替换它们(例如,有角度+与原点的距离),在这种情况下,setter和getter变得有趣 - 你也可以考虑将你的类简化为:xy

struct Point { int x, y; }

简单的设计通常是合适的。


最后,与您的特定问题无关,您的代码以几行不合时宜的行开头......

评论

0赞 Ajay kumar soni 8/6/2021
但我还有其他疑问。由于这是一个指针,因此即使它返回当前调用对象的副本,它也应该更改 y 的值。
0赞 einpoklum 8/6/2021
@Ajaykumarsoni:但是你不回来了。返回 ,取消引用 。现在,类型是 ;但是返回类型是 ,因此会创建并返回副本。this*thisthis*thisPoint&Point
0赞 Ajay kumar soni 8/6/2021
好的,现在我明白了。由于我返回的是 Point 类型,因此 (*this) 将创建一个本地 Point 对象并返回它,然后在此本地对象上调用 setY(2000)。在这个本地返回的对象上,y 值将被更改。最初,我以为既然我从 setX 返回 (*this),那么 setX 将从中返回当前调用对象 (p)。然后它将在同一个对象上调用 setY。但相反,setX 将创建一个本地对象,然后它将返回。如果我在某个地方错了,请纠正我?