关于c ++:operator ++的返回值


Return value of operator++

本问题已经有最佳答案,请猛点这里访问。

我有以下代码被破坏。我可以通过修改代码中的某些行来修复它(参见注释)。问题的原因是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
using namespace std;

class Number{
public:
    int n;
    Number(int a):n(a){}

    //when I change the following to
    //friend Number& operator++(Number& source, int i)
    //then it compiles fine and correct value is printed
    friend Number operator++(Number& source, int i){
        ++source.n;
        return source;
    }
};

int main() {

    Number x(5);
    x++++; //error: no 'operator++(int)' declared for postfix '++' [-fpermissive]
    cout<<x.n;

    return 0;
}


您试图将第二个++应用于第一个调用返回的临时对象。但是,操作数必须通过引用传递,并且不能将临时引用绑定到非常量lvalue引用。

您可能不想"修复"这个问题,因为几乎没有理由修改这样的临时值。但是,您应该在递增之前返回一个值的副本,以给出预期的后递增行为。

前缀运算符应返回一个引用,该引用可以很高兴地绑定到另一个引用,以便++++x;可以按预期工作。


通过写入x++ ++,可以增加内部operator++的返回值。这意味着,如果该运算符的返回值不是可以修改的值,代码就不会编译。

因此,如果声明它返回Number,而不是Number &,那么它就不能被修改(函数的返回值是临时的,而不是lvalue,除非它是引用,因此,接受(非常量)引用的外部运算符+不能将它绑定到按值返回的对象)。


你想做的事很不寻常。post increment通常返回一个右值,表示增量之前的对象(与pre increment相反,pre increment首先递增对象,然后作为左值返回该对象本身)。你基本上是想让后增量的行为方式与前增量相同,原因不明。

通常,您会这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Number {
  int n;
public:
  // Pre-increment
  Number& operator++() {
    ++n;
    return *this;
  }
  Number operator++(int) {
    Number temp = *this;  // capture old value
    ++(*this);
    return temp;
  }
};

根据这个定义,x++++不编译,但当xint时,它也不编译:它实际上没有多大意义。

不管怎样,它对你不起作用的原因如下。x++++解释为

1
operator++(operator++(x, 0), 0)

内部operator++调用返回一个临时Number对象。外部operator++()需要Number&类型的参数,但非常量引用不能绑定到临时的。当您更改声明以使operator++返回Number&—一个lvalue—时,这个返回值可以很高兴地传递给外部operator++调用。


让我们先观察一下,对于int,您也不能像这样链接后增量操作符!

在我解决这个问题之前,让我建议不要写这样的非结构化代码。从现在起一年后,有人会读你的程序,你想让它尽可能容易地摸索。

考虑到x++++实际上类似于operator++(operator++(x, int), int),那么现在发生的情况是,第一个operator++按值返回(导致返回未命名的临时值)。此未命名的临时变量无法绑定到第二个(外部)调用的非常量引用参数,方法查找失败。

最后请注意,您的实现实际上并不实现后缀增量:它实现前缀增量。您应该删除int参数(表示后缀),或者修复实现以返回未修改的值。