为什么重载的“<<”和“++”不能一起工作?

Why don't overloaded "<<" and "++" work together?

首先,我对 C++ 和 OOP 还很陌生,很抱歉问了一些愚蠢的问题。所以,在这里,我重载了“<<”和“++”(后缀和前缀),它们单独工作得很好。但是它们在组合时似乎不起作用。我不明白为什么,++-s return 都是 foo 类型的对象,所以我认为“<<”应该可以正常工作...

#include <iostream>
using namespace std;

class foo
{
    int x;

 public:
    foo()
    {
        x=10;
    }
    
    foo(const foo& f1)
    {
        this->x=f1.x;
        cout<<"OK";      /// testing if it really works
    }

    foo operator ++ ()
    {
        ++x;
        return *this;
    }

    foo operator ++ (int)
    {
        x++;
        return *this;
    }

    
    friend istream& operator>>(istream& in, foo& S);
    friend ostream& operator<<(ostream& out, foo& S);
};

istream& operator>>(istream& in, foo& S)
    {
        in>>S.x;
        return in; 
    }

ostream& operator<<(ostream& out, foo& S)
    {
        out<<S.x;
        return out;
    }
int main()
{

    foo A, B, C;

    cout<<A;
    //cout<<++A;       //error: cannot bind non-const lvalue reference of type 'foo&' to an rvalue of type 'foo'
    //cout<<A++;       //error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'foo')




    return 0;
}

您的流输出重载应将您的 foo 引用作为 const。毕竟,他们不应该修改传入的 foo

friend istream& operator<<(istream& in, const foo& S);

一个非常量引用参数(比如你的 foo& S),必须有一个左值传递给它。由于您的增量运算符 return 是一个 r 值,因此您会看到编译器错误(正是这样说的)。为了能够同时获取 l 和 r 值,您需要更改上面的 const-reference 参数。

此外,您的 prefix 递增运算符应 return 引用:

foo& operator ++ ()
{
    ++x;
    return *this;
}

有关重载的基本规则和习语的更多信息,请阅读此处:

除了scohe001的回答,你的后缀和前缀运算符也需要更正。

前缀运算符应该 return 对正在递增的对象的引用。您正在 return 复制 *this。你的 return 类型应该是 foo& 这样的:

foo& operator ++ ()
{
    ++x;
    return *this;
}

而在后缀运算符中,首先需要记住对象的状态,即在修改前制作对象的副本,然后修改对象,最后return未修改的副本,如这个:

foo operator ++ (int)
{
    foo temp(*this);
    ++x;
    return temp;
}

这是您的代码,已修复。我在更改的地方添加了评论。

#include <iostream>
using namespace std;

class foo {
  int x;

 public:
  foo() { x = 10; }

  foo(const foo& f1) {
    this->x = f1.x;
    cout << "OK";  /// testing if it really works
  }

  // Changed return type
  foo& operator++() {
    ++x;
    return *this;
  }

  // Re-wrote body
  foo operator++(int) {
    foo tmp = *this;
    ++(*this);
    return tmp;
  }

  friend istream& operator>>(istream& in, foo& S);
  friend ostream& operator<<(ostream& out, const foo& S);  // Added const
};

istream& operator>>(istream& in, foo& S) {
  in >> S.x;
  return in;
}

// Matched added const
ostream& operator<<(ostream& out, const foo& S) {
  out << S.x;
  return out;
}
int main() {
  foo A, B, C;

  cout << A << '\n';
  cout << ++A << '\n';
  cout << A++ << '\n';

  return 0;
}

前缀 ++ 和后缀 ++ 的行为不同。这是在定期 int.

测试运算符时观察到的
int x = 5;
std::cout << x++ << '\n';
std::cout << ++x << '\n';

你得到输出:

5
7

后缀增加 returns 原始 值,但仍然增加。前缀增量 returns 增量值。这就是为什么 prefix 需要 return 引用的原因。它 return 是它自己,我们通过引用来做到这一点。

所以在上面的短代码示例中发生的事情是 x 有它的原始值 (5) returned,但是后缀增量仍然递增,所以 x 有一个值6. 然后前缀 print 确保递增的 x 被 returned 并打印 7.

operator<<() 的更改是惯例。打印一个对象时,我不想修改它,所以我把它作为一个引用传递给const。