user12392751
user12392751

Reputation:

I don't understand when the constructor is called in this example

Hi I have been trying to analyze the following code that uses operation overloading.

#include <iostream>
using namespace std;

#define DBG(str) cout << str << endl

class Integer {
    int n;
public:
    Integer(int _n) : n(_n) { DBG("A"); };
    Integer(const Integer& i) : n(i.n) { DBG("B"); };

    Integer& operator=(const Integer& i) { DBG("C"); n = i.n; return *this; };
    Integer& operator+=(const Integer& i) { DBG("D"); n += i.n; return *this; };

    friend Integer operator+(const Integer& a, const Integer& b);
    friend Integer operator*(const Integer& a, const Integer& b);
    friend ostream& operator<<(ostream& os, const Integer& i);

};

Integer operator+(const Integer& a, const Integer& b) {
    DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
    DBG("F"); return Integer(a.n * b.n);
}
ostream& operator<<(ostream& os, const Integer& i) {
    DBG("G"); os << i.n; return os;
}

int main() {
    Integer n1(1), n2(2);
    Integer n = 5 + n1 + 2 * n2;

    cout << n << endl;
}

and the result comes out to be...

A // constructor called when n1 is created
A // constructor called when n2 is created
A // when is this called?
A // when is this called?
F // called when 2 * n2 is operated
A // called when Integer(a.n * b.n) is created in the multiplication function
E // called when 5 + n1 is operated
A // called when Integer(a.n + b.n) is created in the addition function
E // called when (5 + n1) + (2 * n2) is operated
A // called when Integer is created in the addition function
G // called when n is printed using cout
5 // value of n

Now what I'm having trouble with the most is the third and fourth print of A. In the sentence Integer n = 5 + n1 + 2 * n2; the object n is being created and the right value is assigned to n, so a copy constructor should be called? What I think should happen is the constructor should be called for making a temporary object of (5 + n1 + 2 * n2) and then by copying it to n, the copy constructor should be called. What am I understanding wrong?

Could you please explain what is happening? Thank you in advance.

Upvotes: 2

Views: 122

Answers (3)

Amal K
Amal K

Reputation: 4854

Friend function is used in operator overloading only when the first parameter of the operator function is not an object of the target class for which the operator function is defined. In your case, Integer:

Integer operator+(const Integer& a, const Integer& b) {
    DBG("E"); return Integer(a.n + b.n);
}
Integer operator*(const Integer& a, const Integer& b) {
    DBG("F"); return Integer(a.n * b.n);
}

, the first parameter is indeed an object of type Integer which is your target class. What you probably want is to be able to use your Integer object as operands along with primitive integer types. Change your friend function signatures to:

Integer operator+(const int& a, const Integer& b) {
    DBG("E"); return Integer(a + b.n);
}
Integer operator*(const int& a, const Integer& b) {
    DBG("F"); return Integer(a * b.n);
}

Note that a is used instead of a.n because when an operator function is defined as friend, both operands are passed as parameters.(unlike non-friend operator functions where the first operand is a calling object). So the a contains a value of type int and not a value of type Integer.

The anonymous calls to the constructor containing DBG("A") is a result of the implicit conversions happening when 5 and 2 are being converted from int to Integer.

This is unreliable although your code may work. Hope this helps.

Upvotes: 0

Marek R
Marek R

Reputation: 37607

Problem is in this line:

Integer n = 5 + n1 + 2 * n2;

There is no operator+ for int and Integer, but compiler silently did a implicit conversion from int to Integer, since by default all single argument constructors can be used as conversion method. Here is your live code (improved a bit).

This is one of dangerous features of C++ so there is explicit keyword to be used before constructor. If you add it:

explicit Integer(const Integer& i) : n(i.n) { DBG("B"); };

Compiler will report an error since implicit conversion now can't be performed and there is no operator+(int, const Integer&) and operator*(int, const Integer&).

Upvotes: 5

Roy Avidan
Roy Avidan

Reputation: 768

Your operator+ and operator* functions receive an const Integer& as parameter.

When this line is calculated (5 + n1 + 2 * n2) 5 and 2 will be auto-converted to Integer.

If you want them to not be converted, you should consider creating operators for int as parameter.

EDIT: You can also use explicit constructor.

For example: explicit Integer(int _n){...}

//thanks for the comment @formerlyknownas_463035818

Upvotes: 2

Related Questions