Reputation: 7161
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
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
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
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 C
s 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
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
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
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
Reputation: 7846
It calls operator int()
twice because it needs to convert both obj to int before it can add them.
Upvotes: 1
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
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