#include <iostream> using namespace std; class three_d { int x, y, z; public: three_d(int a, int b, int c) {x=a; y=b, z=c; } three_d operator+(three_d op2); friend ostream &operator<<(ostream &stream, three_d &obj); operator int() {return x*y*z;} }; ostream &operator<< (ostream &stream, three_d &obj) { stream << obj.x << ", "; stream << obj.y << ", "; stream << obj.z << endl; return stream; } three_d three_d::operator+ (three_d op2) { x+=op2.x; y+=op2.y; z+=op2.z; return *this; } int main() { three_d a(1, 2, 3), b(2, 3, 4); cout << a << b; cout << b+100 << endl; //31 line cout << a+b << endl; // 32 system("pause"); return 0; } 

In line 31, object b cast to int , because the value of int is to the right, but why does ghost in line 32 work after operator+ executed? After all, there are two objects on both sides, why then the conversion function is called or what is it called there, and even at the end?

  • 2
    @mzarb: Well, const extends only to the argument, so it will not work outside the function. In addition, the compiler itself does nothing, it only follows your instructions, which it understands in accordance with the standard. (So ​​it’s not him who assigns it, it’s you.) - VladD
  • @VladD, that is, the return value does not belong to the scope of the function, and when there is an exit from the function, the temporary object will not be freed or destroyed, since it is no longer part of the function after it is transferred? For example, in this code [ ideone.com/v5BT6R [ AO1]] the temporary object is returned by reference and when outputting some strange values, since all the data apparently collapsed along with the stack. [1]: ideone.com/v5BT6R - mzarb
  • one
    @mzarb: Yeah, it is: returning a reference to an object on the stack, which, of course, dies immediately after the function has completed. Here is a more correct option: ideone.com/iTkjmB --- Even more correct option: ideone.com/lbD7Y9 - VladD

1 answer 1

The problem is that your object amount is not lvalue. It needs to const :

 friend ostream &operator<<(ostream &stream, const three_d &obj); 

Without const cout << a+b not interpreted as

 operator<<(cout, a+b) // ostream &stream, three_d &obj 

but as

 operator<<(cout, (int)(a+b)) // ostream &stream, const int& i 

An object that is not an lvalue can not be used with a non-const reference.


See what happens.

The compiler tries to understand what to call for the expression cout << a + b .

Since a + b is not lvalue, the ostream &operator<< (ostream &stream, three_d &obj) no longer ostream &operator<< (ostream &stream, three_d &obj) . If so, the compiler looks at how it can transform the arguments so that other functions come up.

The compiler tries the known operators << . When he tries ostream &operator<< (ostream &stream, const int &i) , he sees that this operator can be used if the second argument is converted to an int . Since you provided the conversion, this option passes.


Separate from the topic: your addition operator is terrible! You modify the first term!

Imagine if the addition of numbers behaved like this:

 int a = 5; int b = 7; int c = a + b; // здесь внезапно a == 12 

Your code behaves that way.

Here's how:

 three_d three_d::operator+ (three_d op2) { return three_d(x + op2.x, y + op2.y, z + op2.z); } 
  • one
    Excellent analysis. And the question is good. A visual demonstration of the horror C ++ is. - avp
  • one
    @VladD, and legs (IMHO, of course) grow from the "good" desire to redefine operations . Here in Java, for example, it is not, and the language is really simpler. - avp 7:03 pm
  • one
    @avp: and yet, it seems to me, from the slogan "you do not pay for what you were not asked for" - which translates into overly general functionality (modern compilers still do not know how to optimize STL as it could be done manually, not to mention the boost). - VladD
  • one
    @mzarb: No, that you, no copies are created. The idea is this (if I understand correctly). Let's look at this simplified code: void Change (int & x) {x + = 1; } void Print (const int & x) {cout << x; } Change (2 + 3); Print (2 + 3); Call Change(2 + 3); meaningless, because in the absence of const, the value of the expression can be changed, and there is no way to see the result of this change. Therefore, this code seems to be wrong. Here the standard also decided not to pass such code. ... - VladD 5:43 pm
  • one
    @mzarb: ... Call Print(2 + 3); on the contrary, it is quite normal: you promise not to change the value, since the Print argument is const. That is, there is no logical error. If we wrote int x = 2 + 3; Change (x); - this is again normal, because now the argument is lvalue, it can be checked after the change. - VladD 5:44 pm