【问题标题】:Object becomes immutable when returning *this from a setter method当从 setter 方法返回 *this 时,对象变得不可变
【发布时间】:2021-10-11 01:03:16
【问题描述】:

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

#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?

【问题讨论】:

  • setXsetY 返回它们的点按值,而不是通过引用。这意味着当您return *this 时,您会返回您正在调用该方法的对象的副本。
  • 您返回的是按值的对象,而不是按引用Point 包含 *this 的副本。如果您希望链接您的操作,则返回类型应为 Point&amp;
  • 请注意,通常像 setX(int)setY(int) 这样的 setter 方法根本不返回任何内容,即它们的返回类型通常是 void。让他们返回 Point 是合法的 C++,但它会让人们感到困惑。
  • @JeremyFriesner:两种风格的 setter 都很常用(坦率地说,我都不喜欢)。
  • 我想说,对于像 2D 点这样无处不在且简单的东西,使用 getter 和 setter 将其封装在私有数据中似乎有点过头了。为什么不让成员公开并完成它?

标签: c++ class pointers this


【解决方案1】:

因为setX(和setY)按值返回。在p.setX(1000).setY(2000); 中,p.setX(1000) 返回一个临时的Point(从*this 复制),在该临时*this 上调用setY,来自setY 的任何修改都与p 无关。

将它们更改为传递引用。

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

【讨论】:

  • 所以你说 p.setX(1000) 正在对其从 *this 复制的对象进行更改。既然它正在更改其本地对象副本中的值,那么为什么更改会反映在 p.x 值中。
  • @Ajaykumarsoni 不,我说的是setYp.setX(1000)更改p.x,然后它返回一个副本,然后在副本上调用setY(2000),副本的y被更改。副本立即销毁,只留下p.x 更改。
  • 好的,现在我明白了。由于我返回的是 Point 类型,因此 (*this) 将创建一个本地 Point 对象并返回它,然后在此本地对象上调用 setY(2000)。并且在这个本地返回的对象上,y 值将被更改。最初,我认为既然我从 setX 返回 (*this),那么 setX 将从它返回当前调用对象 (p)。然后它会在同一个对象上调用 setY。而是 setX 将创建一个本地对象,然后它会返回。如果我在某个地方错了,请纠正我?
  • @Ajaykumarsoni 你是对的。这就是为什么更改为按引用返回可以解决问题的原因;它使setX 返回当前对象而不是副本。
【解决方案2】:

原因是您的setX()setY() 方法返回Point - 它们返回您对象的副本。因此,您的 setY()y 成员设置为您的点的临时副本,而不是原始点。

您可以通过更改以下签名来纠正此问题:

Point setX(int x)

到:

Point& setX(int x)

setY() 也是如此。您会注意到返回类型现在是 Point&amp; - 对 Point 对象的引用。

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

struct Point { int x, y; }

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


最后,与您的具体问题无关,您的代码以一些不合时宜的行开头...

【讨论】:

  • 但我还有其他疑问。因为这是一个指针,所以即使它返回当前调用对象的副本,它也应该改变 y 的值。
  • @Ajaykumarsoni:但你不会返回this。您返回 *this,即取消引用 this。现在,*this 的类型是Point&amp;;但返回类型是Point,因此会制作并返回一个副本。
  • 好的,现在我明白了。由于我返回的是 Point 类型,因此 (*this) 将创建一个本地 Point 对象并返回它,然后在此本地对象上调用 setY(2000)。并且在这个本地返回的对象上,y 值将被更改。最初,我认为既然我从 setX 返回 (*this),那么 setX 将从它返回当前调用对象 (p)。然后它会在同一个对象上调用 setY。而是 setX 将创建一个本地对象,然后它会返回。如果我在某个地方错了,请纠正我?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-19
  • 2022-12-04
  • 2011-07-02
  • 1970-01-01
相关资源
最近更新 更多