Search code examples
c++polymorphismoperator-overloadingoverloading

C++ unexpected output elicited by the multiple operator overloading usage in a single line


I'm a student who is learning C++ (especially the operator overloading part). During my study, I found the following code that uses operator overloading doesn't make an expected output. At first, the code with which I have trouble is the...

#include <iostream>
using namespace std;

class Power {
    int kick;
    int punch;
public:
    Power(int kick = 0, int punch = 0) {
        this->kick = kick; this->punch = punch;
    }
    void show();
    Power operator << (int n); 
};

void Power::show() {
    cout << "kick=" << kick << ',' << "punch=" << punch << endl;
}


Power Power::operator <<(int n) {
    kick += n;
    punch += n;
    return *this; 
}

int main() {
    Power a(1, 2);
    a << 3 << 5 << 6; 
    a.show();
}

The overloaded operator << was designed for adding the integer to all member variables of the instance. I installed << operators three times in a single line such as a + 3 + 5 + 6. I expected the output will be kick=15,punch=16, but the console shows kick=4,punch=5 as a result of that code. It seems that only the first << operation works and the behind code doesn't work at all as I expected like parallelly connected math operators.

I know this unexpected behavior of the suggested code will be simply fixed by adding &(reference) to the operator overloading like Power& operator << (int n); , but I can't grasp why these make totally different outputs. When I utilized the debugging feature in Visual Studio, the calculated outputs since the second overloaded operation aren't applied to the target a, but I couldn't find more answers beyond just the behavior.


Solution

  • As you discovered, you need that & to return a reference of this.

    What really happens?

    a << 3
    

    creates a new Power object since you return Power instead of Power&.

    Let's call that new object b. Then what happens next is:

    b << 5
    

    Again, that returns a new object of type Power. Let's call this one c. Finally this happens:

    c << 6
    

    The expression returns c with the correct result, but you do not capture that value. You could do so with:

    c = a << 3 << 5 << 6;
    

    Then verify that c is what you expect:

    c.show();
    

    You could also capture b like so (since you're learning, just don't write such expressions, it's very cryptic):

    c = (b = a << 3) << 5 << 6;
    

    Forgetting the & in an operator is a common mistake. Or rather, some operators return a copy (operator + (...)) and others are expected to return a reference (operator += (...)) and it's often that we copy/paste and forget to tweak the return value and it looks like it works in most cases and when you daisy chain it starts failing in really strange ways...