【问题标题】:Do I have to return a reference to the object when overloading a pre-increment operator?重载预增量运算符时是否必须返回对对象的引用?
【发布时间】:2011-09-16 13:41:03
【问题描述】:

我可以使用吗:

MyClass& MyClass::operator++ () {
    a++;  // private var of MyClass
    return (*this);
}

也可以是:

MyClass MyClass::operator++ ();

有什么区别?


感谢您的回答。我还有一个问题。

很多人都会这样做:

MyClass& MyClass::operator++();
MyClass MyClass::operator++(int);

这不是不合逻辑吗?如果可以的话,请举一些例子。

我知道第一个版本是前增量,第二个是后增量,但我问为什么第一个返回引用而第二个没有?它是在同一个代码(类)中,并且使用同一个代码。

【问题讨论】:

  • 好问题。我仍在等待一个答案,说明为什么第二个不会起作用。
  • @Mark,您将不得不等待很长时间。第二个会工作得很好。这实际上是一个设计问题——他应该做什么,而不是他必须做什么。他可能应该返回一个引用,但他可能做无数其他事情,包括他的第二个例子。
  • @Rob,你的答案是我希望看到的——你已经得到了我的 +1。
  • name3r,你应该得到一本 C++ 书。您的问题是基本问题之一,一本书应该回答它们。也就是说,第一个版本用于前置增量,而第二个版本用于后置增量(dummy-int 参数)。
  • 至于您的第二个问题,后增量不会返回引用,因为这不会正确地为运算符建模。后增量返回 prior 值而不是 current 值。根据定义,返回引用将返回当前值。

标签: c++ function operator-overloading


【解决方案1】:

不,当您重载预增量运算符时,您没有返回对您的对象的引用。事实上,你可以返回任何你想要的东西,MyClassintvoid,等等。

这是一个设计问题——你必须问问自己,你能够返回的对类用户最有用的东西是什么。

作为一般规则,类运算符在引起混淆最少时最有用,也就是说,当它们对基本类型进行最相似的运算符时。在这种情况下,基本类型上的预增量运算符:

int  i = 7;
j = ++i;

递增变量,然后返回新值。如果这是您希望 MyClass 拥有的唯一用途,那么返回您的类的副本就足够了。

但是,基本类型的预增量运算符实际上返回一个左值。所以,这是合法的:

int i = 7;
int *p = &++i;

如果你想支持这样的操作,你必须返回一个引用。

您是否有不想返回参考的特定原因?对于您的特定班级,这不是一个结构良好的概念吗?如果是这样,请考虑返回void。在这种情况下,这个表达式:++myObject 是合法的,而这个 myOtherObject = ++myObject 是不合法的。

【讨论】:

【解决方案2】:

问题二:

Prefix 按预期返回一个引用。 后缀返回一个副本以与后缀运算符的行为一致。

简单分解为 int:

int c = 0;

if(++c)
{
   // true, prefix increments prior to the test
}

c = 0;

if(c++)
{
   // false, c now == 1, but was incremented after the test
}

在类中实现此行为需要返回一个副本,因为后缀运算符将修改对象的状态。

如果程序不需要真正的后缀操作,你当然可以随意实现。虽然有编写这些运算符的标准方法(大多数 C++ 程序员都理解),但实际上并没有什么能阻止您以不同的方式实现它。

围绕(obj++)++ 提供的有关不正确功能的论点并不重要,因为该代码甚至不会针对 POD 类型进行编译(至少在 Visual Studio 2010 中),因为对于 POD 类型,会返回一个副本,并且临时副本不能单独用作左值。

但是,对于前缀运算符,引用是首选返回,因为它允许链接操作 (++(++obj)) 的正确行为。

【讨论】:

    【解决方案3】:

    您可以退回任何您想要的东西。 void,对自我的引用,自我的副本,其他东西。无论您喜欢(或需要)哪个。

    如果您计划在链式表达式(如(++obj).something())中使用++ 运算符,则返回一个引用。如果你不这样做,那么void 就可以了。

    请记住,最后,运算符就像普通方法一样:只要尊重它们的原型,您就可以对它们做任何您想做的事情。

    【讨论】:

    • @name3 - 最好的方法是为你的班级做看起来合乎逻辑的事情。您甚至不必增加该值,您也可以乘以 42,如果这对您的类型来说是 明显 的事情。例如,boost::filesystem 重载 operator/ 以连接路径而不是使用它进行除法。
    【解决方案4】:

    这不是强制性的,但我们应该尽量让运算符重载直观,它应该按照被重载的运算符工作。

    如果我们这样做 诠释 i = 10; 我++ = 0 然后第二个语句是不允许的,它说它需要左值,因为 i++ 表示 i 的旧状态不是存储... 而 ++i = 0 完全可以正常工作.. 因此,为了使其与实际操作符前缀版本保持同步,必须返回引用,以便其返回值可以在表达式中被视为左值。

    【讨论】:

    • ++i = 0 无法正常工作,并且遇到与i++ = 0 类似的问题。每个序列点只能设置一次变量。 "更新左操作数的存储值的副作用应该发生在前一个和下一个序列点之间。"
    【解决方案5】:

    是的,您应该通过引用返回。 *this 周围不需要括号。

    编辑:回复您的评论...您没有必须通过引用返回。但总的来说,与此类运算符的内置语义相比,我们遵循一些指导方针,使我们的类表现得“如预期”。你可能想看看http://www.parashift.com/c++-faq-lite/operator-overloading.html

    【讨论】:

    • 好的,但是你能解释一下为什么吗?举一些实际的例子?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 2011-07-23
    • 2020-08-26
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多