1

Firstly, i'm pretty new to C++ and OOP, so sorry if asking silly questions. So, here it is, I overloaded the "<<" and "++" (postfix and prefix) and they work fine alone. But they seem to not work when combined. I don't get why, both ++-s return a foo type object, so I thinked that "<<" should work fine...

#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;
}

3 Answers3

3

Your stream output overload should take your foo references as const. After all, they shouldn't be modifying the foo's passed in:

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

A non-const reference parameter (like your foo& S), must have an l-value passed to it. Since your increment operator returns an r-value, you're seeing the compiler error (which says exactly this). To be able to take both l and r-values, you need to make the change to a const-reference parameter above.

In addition, your prefix increment operator should return by reference:

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

For more on the basic rules and idioms for overloading, read here: https://stackoverflow.com/a/4421719/2602718

scohe001
  • 15,110
  • 2
  • 31
  • 51
  • It works now, thank you, but why is the const necessary? Could you explain please? –  Mar 23 '21 at 20:52
  • @star I tried to explain in my second paragraph. If you let me know what part of that you're having trouble understanding, I can try to elaborate. – scohe001 Mar 23 '21 at 21:06
  • Mostly speculation: Taking a non-`const` reference to a temporary object (like the `foo` returned by `A++` in the expression `std::cout << A++;`) implies that you want to make changes to that temporary `foo` inside the function. That is most probably a programmer error so I think that's why decided not to allow it. When taking arguments by reference, always make them `const` unless you actually want to make changes to the object in the function. – Ted Lyngmo Mar 23 '21 at 21:11
3

In addition to scohe001's answer, your postfix and prefix operators also need correction.

Prefix operator should return a reference to the object being incremented. You're returning a copy of *this instead. Your return type should be foo& as such:

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

And in the postfix operator, you need to first remember the state of the object, i.e. make a copy of the object before modification, and then modify the object, and finally return the unmodified copy, like this:

foo operator ++ (int)
{
    foo temp(*this);
    ++x;
    return temp;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Muratcan Akcay
  • 155
  • 2
  • 12
2

Here's your code, fixed up. I added comments where I made changes.

#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;
}

Prefix ++ and postfix ++ behave differently. This is observed when testing the operators out on a regular int.

int x = 5;
std::cout << x++ << '\n';
std::cout << ++x << '\n';

You get the output:

5
7

Postfix increment returns the original value but still increments. Prefix increment returns the incremented value. This is why prefix needs to return a reference. It returns itself, and we do that with a reference.

So what happened in the short code example above was x had its original value (5) returned, but the postfix increment still incremented, so x had a value of 6. Then the prefix print ensured that the incremented x was returned and it printed 7.

The change to operator<<() is convention. When printing an object, I don't want to modify it, so I pass it as a reference to const.

sweenish
  • 4,793
  • 3
  • 12
  • 23
  • Thanks, got it, from now on when overloading "<<" i will put const. But why exactly does it not work without const? –  Mar 23 '21 at 20:55
  • I don't have a "quote the standard" answer. It likely has something to do with how the original function you're overloading is written. It's just good practice to mark your parameters `const` when you don't intend to modify them. And that is the case when placing data in an output stream. – sweenish Mar 23 '21 at 21:00