when working with operator <<(for standard output) in C , how comes that the parameter const data_type& object can work with VALUES AND OBJECTS, but if i do data_type& object or data_type&& object it doesnt work? If lets say i have Complex Class, and i have defined operator << and operator for addition of two complex numbers and my functions for these operator are declared as:
friend ostream& operator<<(ostream& out, Complex& c);
Complex operator (Complex&c2);
and i do something like
cout << c1 * c2; //doesnt work
cout << c1; cout << c2; //it works
but when I put in operator<< const Complex& c
, both of these work, why is that?
CodePudding user response:
The fundamental reason of why/how this works is operator precedence. In the below example i have explained step by step how the program works. At the end of the program i have also explained why in your case/example it doesn't work while in my case it does.
#include <iostream>
class Complex
{
//friend declaration for overloading different operators
friend std::ostream& operator<<(std::ostream& os, const Complex&);//note that the second argument is "reference to const"
friend Complex operator*(const Complex& obj1, const Complex& obj2);
public:
//lets overload operator as member function just for example in this case
Complex operator (const Complex& obj2)
{
std::cout << "Overloaded operator called"<<std::endl;
return Complex();
}
};
//note that the second argument is a reference to const
std::ostream& operator<<(std::ostream& os, const Complex& obj)
{
std::cout<<"Overloaded operator<< called"<<std::endl;
return os;
}
Complex operator*(const Complex& obj1, const Complex& obj2)
{
std::cout<<"Overloaded operator* called"<<std::endl;
return Complex();
}
int main()
{
//create Complex object
Complex c1, c2;
std::cout << c1; //this uses overloaded operator<<
Complex c3;
c3 = c1 c2; //this uses overloaded operator
/*Explanation of c3 = c1 c2;
Here due to operator precedence objects c1 and c2 are grouped together. That is, since operator has higher precedence that operator=
c1 and c2 are grouped together. So the above is equivalent to writing c3 = (c1 c2);
Next assignment operator= is used to assign the value of (c1 c2) to c3.
*/
c3 = c1 * c2; //this uses overloaded operator*
/*Explanation of c3 = c1 * c2;
Since operator* has higher precedence than operator= the objects c1 and c2 are grouped together and the above statement is equivalent to
writing c3 = (c1 * c2);
Next assignment operator= is used just like in the last case.
*/
//now lets take a look at your question statment
std::cout << c1 * c2 ; //this works because the second argument is a reference to const in my example(unlike yours)
/*Explanation of std::cout << c1 * c2;
Now again, operator precedence is the fundamental reason here. Since operator* has higher precednece than operator<< the objects c1 and c2
are grouped together and so the above essentially means std::cout << (c1 * c2);
Note that our overloaded operator* returns a Complex object by value.
Next since the result that was returned in the last step is a "temporary" Complex object but we have overloaded operator<< with its
second argument as reference to const, this works. The important thing to note is that this works in my example because a reference to const
can be bound to a temporary object. But it doesn't work in your case(example) because in your case the overloaded operator<< has its second argument
as reference to nonconst and we can only bind a reference to a nonconst to an lvalue.
*/
return 0;
}
The output of the above program can be seen here.
Let's see in step by step manner for my above given example what is going on:
Case I: For std::cout << c1;
Since we have overloaded operator<<
it will be used.
Case II: For c3 = c1 c2;
Here due to operator precedence objects c1
and c2
are grouped together. That is, since operator
has higher precedence that operator=
objects c1
and c2
are grouped together. So the above is equivalent to writing c3 = (c1 c2);
Next assignment operator=
is used to assign the value of (c1 c2)
to c3
.
Case III: For c3 = c1 * c2;
Since operator*
has higher precedence than operator=
the objects c1
and c2
are grouped together and the above statement is equivalent to
writing c3 = (c1 * c2);
Next assignment operator=
is used to assign the value of (c1 * c2)
to c3
.
Now next case is regarding your question, look at it carefully.
Case IV: For std::cout << c1 * c2 ;
Now again, operator precedence is the fundamental reason here. Since operator*
has higher precedence than operator<<
the objects c1
and c2
are grouped together and so the above essentially means std::cout << (c1 * c2);
Note that our overloaded operator*
returns a Complex
object by value.
Next since the result that was returned in the last step is a "temporary" Complex object but we have overloaded operator<< with its second argument as reference to const, this works since a reference to const can be bind to a temporary object.
The important thing to note is that this works in my example because a reference to const can be bound to a temporary object. But it doesn't work in your case(example) because in your case the overloaded operator<<
has its second argument as reference to nonconst and we can only bind a reference to a nonconst to an lvalue.