Rohit
Rohit

Reputation: 7161

C++ operator overloading

Why does the below C++ program output "ACCA"? Why is operator int() called twice?

#include "stdafx.h"
#include <iostream>

using namespace std;

class Base {
public:
    Base(int m_var=1):i(m_var){
        cout<<"A";
    }
    Base(Base& Base){
        cout<<"B";
        i=Base.i;
    }
    operator int() {
        cout<<"C";
        return i;
    }
private:
    int i;
};

int main()
{
    Base obj;
    obj = obj+obj;
    return 0;
}

Upvotes: 15

Views: 936

Answers (9)

Baltasarq
Baltasarq

Reputation: 12212

how does below C++ program computes to "ACCA" ?

The first letter shown is 'A'. This output is related to this line:

Base obj;

... in which you are creating a new instance of Base.

The next line is a bit complicated:

obj = obj+obj;

Normally, this is translated to obj.operator+( obj ), but you don't have operator + overloaded in class Base, so this translation is not valid. The remaining possibility is that operator + is actually the numeric add operator.

And yes, this is possible, since you have provided a cast to int. So it is possible to convert each term of the equation in an int... and therefore operator int is called twice. The actual number of times operator int is called depends on the optimizations activated. For example, the compiler could realise that both terms are the same, and then create a new temporary once the operator int has been called the first time. In that case, you would see CA instead of CC.

Finally, the assignment expression obj.operator=( temp ) is executed. And here the keyword is temp. In order for the default operator= to work, since it is not overloaded, you have to have a Base object at the right. It is actually possible to have it, since Base uses an int to build new instances. Okay, so the result of obj + obj was an int (say it is called 'x') number, and the compiler creates a temporary object of class Base which is constructed with number x, as the following line was executed:

Base temp( x );

That's the way the final letter seen is an 'A'. Again, many compilers can avoid the building of temporaries on some cases, so it is possible not to see an 'A' at the end.

Note that this line:

obj = obj + obj

Was thus decomposed in:

int x = ( (int) obj ) + ( (int) obj );
Base temp( x );
obj = temp;

The final instruction has the result of as if the memory in which obj sits will be occupied with the contents of temp (that's the role of the default copy constructor, which executes operator= for each member of the class, see again the 'rule of three').

Operator overloading involves a lot of issues that maybe are not foreseen if you don't have a more or less deep knowledge of the language, as you can see. Take also into account that languages like Java totally prevent its use, while C# permits it from a controlled perspective.

Upvotes: 2

IanPudney
IanPudney

Reputation: 6021

operator int() is called twice because you haven't overloaded operator+. The compiler doesn't know how to add a Base to a Base, so they are converted to int (since you taught it how to do that), which it does know how to do. The following code prints ADA:

#include <iostream>

using namespace std;

class Base {
public:
    Base(int m_var=1):i(m_var){
        cout<<"A";
    }
    Base(Base& Base){
        cout<<"B";
        i=Base.i;
    }
    operator int() {
        cout<<"C";
        return i;
    }
    int operator+(Base& Base)
    {
        cout<<"D";
        return i+Base.i;
    }
private:
    int i;
};

int main()
{
    Base obj;
    obj = obj+obj;
    return 0;
}

Upvotes: 9

Andy Prowl
Andy Prowl

Reputation: 126432

First, this line:

Base obj;

Default-constructs object obj by picking the constructor that accepts an integer, with default value 1. This is responsible for the first A being printed to the standard output.

Then, this expression:

obj + obj

Requires picking a viable overload of operator +. In this case, since obj has a user-defined conversion to int, the built-in operator + is picked, and both arguments are converted to int. This is responsible for the two Cs being printed to the standard output.

Then, the assignment to obj in:

obj = obj + obj

Needs to invoke the implicitly generated operator = for Base. The implicitly generated operator = has signature:

Base& operator = (Base const&);

This means that the expression on the right side of the equal sign, which is of type int, must be converted into a temporary Base object from which obj is assigned (the reference parameter of the implicitly-generated operator = is bound to this temporary).

But the creation of this temporary from an int in turn requires invoking the converting construction of Base that accepts an int again, which is responsible for the second A being printed to the standard output.

Upvotes: 30

KamikazeCZ
KamikazeCZ

Reputation: 724

The first A comes from

Base obj;

The two Cs come from converting obj in obj+obj to int as you didn't overload the operator +.

The last A comes from obj = conversion of the resulting int to obj.

Upvotes: 1

Oktalist
Oktalist

Reputation: 14714

obj = obj+obj;
      ^^^--------obj converted to int here
          ^^^----obj converted to int here
^^^^^------------Base(int) ctor and default operator= called here

Overloading cast operators is not generally a good idea unless you understand the costs and know for a fact that the benefits in your specific case outweigh them.

Upvotes: 5

Reed Copsey
Reed Copsey

Reputation: 564413

When you construct the object, you get the first "A":

 Base obj;

When you specify to add obj+obj, the compiler needs to figure out a way to use + on obj. Since you didn't override an operator+ for Base, the conversion to int() gets called for each side of the equation:

obj+obj

This prints "CC".

Then, you assign to obj, which is of type Base, so the constructor which can accept an int (i + i from the int() operator) is run, which prints "A":

obj = obj+obj; // Assignment prints "A"

Upvotes: 5

Stochastically
Stochastically

Reputation: 7846

It calls operator int() twice because it needs to convert both obj to int before it can add them.

Upvotes: 1

Maresh
Maresh

Reputation: 4712

It's call once per operand, it doesn't matter if it is the same instance.

 obj = obj+obj;

It "casts" the first operand to an int, and then the second one.

You need to overload the operator + if you want to avoid this implicit cast.

Upvotes: 1

Daniel Earwicker
Daniel Earwicker

Reputation: 116674

You refer to obj twice in the expression obj+obj and each such reference has to be converted to an integer.

It's not impossible (although it is a horrible idea) that such a conversion could be "stateful" - that is, it could by design return a different value each time it is called. After all, the value represented by obj may change (it could be a counter or something like that). So the compiler has to evaluate it afresh for each reference.

Upvotes: 1

Related Questions