Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

operator overloading using ostream and chaining. Why return by reference?

There are many questions and answers for this, but I can't really find why we need to return by reference.

If we have (assume operator is already correctly overloaded for an object MyObject) :

    MyObject obj1;
    MyObject obj2;
    cout << obj1 << obj2;

Now, there will be subexpressions like ((cout << obj1) << obj2)); The question is why can we not return by value ? (Ok, let's assume that it's allowed return ostream as value) If cout << obj1 return a stream object instead of a reference, what is the difference ? Why is chaining impossible then ? Just as with overloading of the '=' operator, we can't chain like A=B=C=D if we return by value. Why ?


Thank you for answers. I realize that I can chain without return by reference, but my output is quite different when overloading '='. If I write :

    class Blah{
    public:
       Blah();
       Blah(int x, int y);
       int x;
       int y;
       Blah operator =(Blah rhs);
     };
     Blah::Blah(){}
     Blah::Blah(int xp, int yp){
       x = xp;
       y = yp;
     }
     Blah Blah::operator =(Blah rhs){
       Blah ret;
       ret.x = rhs.x;
       ret.y = rhs.y;
       return ret;
     }
    int main(){

      Blah b1(2,3);
      Blah b2(4,1);
      Blah b3(8,9);
      Blah b4(7,5);
      b3 = b4 = b2 = b1;
      cout << b3.x << ", " << b3.y << endl;
      cout << b4.x << ", " << b4.y << endl;
      cout << b2.x << ", " << b2.y << endl;
      cout << b1.x << ", " << b1.y << endl;
          return 0;
     }

The output from this is : 8,9 7,5 4,1 2,3

But if I overload with return by reference and set the parameter as reference, and modify and return *this when overloading instead, I get : 2,3 2,3 2,3 2,3

What is the reason no objects are altered in the first example ? Is it because of lvalues vs rvalues ? How about shorthand operators in comparison?


Ok, another update. As mentioned, the correct result should be 2,3 for all. However, if I write the overloaded operator as :

     Blah Blah::operator =(Blah rhs){
       x = rhs.x;
       y = rhs.y;
       return *this;
     }

Then, I will get correct results. (2,3 2,3 2,3 2,3). What happens to *this ? The overloaded operator update the lhs with rhs in the overload function, but returning *this seem to be pointless. Where does *this end up in : b3 = b4 = b2 = b1 ? Will it try to return to the left, so that it actually returns nothing when the chain reaches b3 (That will try to return to the left)?

like image 526
user1511956 Avatar asked Dec 16 '22 14:12

user1511956


2 Answers

The main reason is because returning by value makes a copy, and iostream objects are not copyable. They have state and identity, and it's not clear what copying them should mean: the object contains (logically, at least) its position in the stream, so if I create a copy, I have two objects which will write at the same position in the stream.

like image 50
James Kanze Avatar answered May 11 '23 02:05

James Kanze


Returning by value does not prevent chaining. But if you return by value, you're returning a copy, which is generally not what you want in this case.

like image 25
Oliver Charlesworth Avatar answered May 11 '23 00:05

Oliver Charlesworth