为啥我们在重载赋值中使用 return *this? [复制]

Posted

技术标签:

【中文标题】为啥我们在重载赋值中使用 return *this? [复制]【英文标题】:Why do we use return *this in overloaded assignment? [duplicate]为什么我们在重载赋值中使用 return *this? [复制] 【发布时间】:2014-03-22 08:30:27 【问题描述】:

我是计算机科学专业的学生。请在回答之前完整阅读我的问题

今天在 C++ 课上,我们学习了重载运算符,尤其是赋值运算符,我的教授说了一些他不喜欢的话:“相信我。”他说出这句话时提到了return *this 约定。

我问,“但是为什么?”他的回答几乎是,“因为它是。”

我对这个答案不满意。

考虑以下几点:

class length

private:
     int inches, feet, yards;
public:
    //getters, setters, etc.
    Length operator=(const Length& Q)
    
        this->inches = Q.inches;
        this->feet = Q.feet;
        this->yards = Q.yards;
        return *this;
    
;

我通过无数问题和至少 3 本 C++ 书籍胡乱理解,“约定”之所以存在是因为它允许链式分配,但为什么需要以及如何是吗?

一个更深入的问题是this 如何对类的属性(IE this->inches)有单独的“子指针”(我的术语,不是官方的)?这是如何运作的? this->inches 只是一个偏移量还是什么?

我的教授和我真的很感激一个不仅仅是“因为它是如何完成的”的答案。

请,谢谢

编辑:我以为我写的问题很清楚;但是,根据我收到的回复,我认为存在误传。我正在寻求了解约定的来源(我相信源于 C)以及为什么会这样。

【问题讨论】:

@MartinJ。 - 很好的发现,但对于其他投票结束的人,请查看已接受的答案。然后考虑投反对票,投一个正确的票。 如果你的教授不能给出比“因为它是这样完成的”更好的答案,你应该找一位新教授。 我个人的看法是,返回一个指针在技术上是正确的做法,但这太“C”了。必须像其他流行语言一样,尽量隐藏指针的存在。 @JoshuaClayton:那个'C'是什么样的?当您在 C 中从一个变量到另一个变量时,表达式的类型不是指针(当然,除非您分配给 的东西是 指针)。 一个赋值只需要两个操作数。对象和单个参数实现了这一点。返回指针将与此引用一样有效。返回 void 对我来说更有意义。 【参考方案1】:

赋值是一个表达式。它既有效果(将一些数据从右侧复制到左侧)也有值。除非您想打破常规并让奇怪的事情发生,否则该值就是左侧的东西(即this)。这样,如果 a 从分配中变为真,则 if (a = b) 为真,并且 a = b = cc 分配给 ab

最好通过引用而不是按值返回this,如this answer 中所述,这是为了避免不必要的复制。

【讨论】:

是的。返回值的赋值有助于简洁。 出于兴趣:在某些语言(如 Python)中,赋值 不是 表达式:它是一种语句,它有副作用,但它没有值,因为它不能在语句中使用。 正式地说,a = b = c 不会将c 分配给ab。它只将c 分配给b,然后将b = c 的结果分配给ab = c 的结果可能与 c 本身完全不同。即使使用内置运算符,a 也被分配 c 转换为 b 的类型,这也不是 c 本身。例如,在int a; unsigned char b; a = b = -1; 变量a 将收到值。 提及void operator=(bob const&) 也可能是值得的。 请注意,返回类型是支持(a = b) = c; 的非常量引用,它对C 中的int 有效(重载运算符时,按int 的方式操作 i>),该表达式是否真的有意义……否则您可以考虑将(a = b).change() 作为一个选项……但我还没有看到在生产代码中很好地使用从operator= 返回的非常量引用【参考方案2】:

共识似乎是 operator= 传统上返回 *this 以启用以下构造:

a = b = c

这是 C 的传统行为扩展到类。 顺便说一句,你operator=的签名应该是:

Length& operator=(const Length& Q);

因为你不想创建一个新的临时对象sa返回值

【讨论】:

只是出于好奇,为什么我不想返回 TNO(临时无名对象)?在operator+(const Length& Q) 中,我们肯定是故意返回一个 TNO,那么为什么不在这里分配呢?【参考方案3】:

既然你对答案不满意“因为是”,那我给你换一个吧:

重载操作符时,按照int的做法

该建议的原因是遵循最小意外原则,人们习惯于操作员以特定方式查看和表现现有类型。当他们将运算符与您的类型一起使用时,隐含的期望是它的行为相同。

现在下一个问题是为什么int 会这样?对此我没有明确的答案。它启用了一些花哨的语法,例如:(a = 3) = 5++(a = 3)(x = y).change(),但尚不清楚这三种情况下的真正价值是什么。第一种情况可以直接赋值5,另外两种情况将表达式重写为两个单独的表达式会使代码更具可读性。

我故意避免在前面的参数中使用 a = b = c 的情况,因为这种情况支持运算符应该产生一个 的想法,或者一个引用,以便它可以在以后使用赋值,但是约定是返回一个可修改的引用,上面的表达式不需要这个。 const & 足以支持上述语法。 [然后,真的需要这种语法吗?将其拆分为两个语句的成本是多少?它不是更具可读性吗? (在许多情况下可能会更好,在某些情况下可能不会)]。

无论如何,要带回家的教训是遵循最不意外的原则,无论导致所有基本类型或其他标准类型的这种行为的基本原理是什么,一旦它成为一个成语,它还是跟着就好了。

【讨论】:

以上是关于为啥我们在重载赋值中使用 return *this? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?

重载+号运算符出错

从复制赋值重载中通过引用返回

c++中为啥赋值运算符重载返回类型是引用

Javaee 方法的格式和注意事项

运算符重载详解