return value of operator overloading in C++
I have a question about the return value of operator overloading in C++. Generally, I found two cases, one is return-by-value, and one is return-by-reference. So what's the underneath rule of that? Especially at the case when you can use the operator continuously, such as cout<<x<<y
.
For example, when implementing a + operation "string + (string)". how would you return the return value, by ref or by val.
Solution 1:
Some operators return by value, some by reference. In general, an operator whose result is a new value (such as +, -, etc) must return the new value by value, and an operator whose result is an existing value, but modified (such as <<, >>, +=, -=, etc), should return a reference to the modified value.
For example, cout
is a std::ostream
, and inserting data into the stream is a modifying operation, so to implement the <<
operator to insert into an ostream
, the operator is defined like this:
std::ostream& operator<< (std::ostream& lhs, const MyType& rhs)
{
// Do whatever to put the contents of the rhs object into the lhs stream
return lhs;
}
This way, when you have a compound statement like cout << x << y
, the sub-expression cout << x
is evaluated first, and then the expression [result of cout << x ] << y
is evaluated. Since the operator <<
on x
returns a reference to cout
, the expression [result of cout << x ] << y
is equivalent to cout << y
, as expected.
Conversely, for "string + string", the result is a new string (both original strings are unchanged), so it must return by value (otherwise you would be returning a reference to a temporary, which is undefined behavior).
Solution 2:
To attempt an answer to your question regarding strings, the operator+() for strings is almost always implemented as a free (non-member) function so that implicit conversions can be performed on either parameter. That is so you can say things like:
string s1 = "bar";
string s2 = "foo" + s1;
Given that, and that we can see that neither parameter can be changed, it must be declared as:
RETURN_TYPE operator +( const string & a, const string & b );
We ignore the RETURN_TYPE for the moment. As we cannot return either parameter (because we can't change them), the implementation must create a new, concatenated value:
RETURN_TYPE operator +( const string & a, const string & b ) {
string newval = a;
newval += b; // a common implementation
return newval;
}
Now if we make RETURN_TYPE a reference, we will be returning a reference to a local object, which is a well-known no-no as the local object don't exist outside the function. So our only choice is to return a value, i.e. a copy:
string operator +( const string & a, const string & b ) {
string newval = a;
newval += b; // a common implementation
return newval;
}