intro2alg
intro2alg

Reputation: 41

C++ overriding the assignment operator

To understand constructor and assignment, I wrote a very simply testing code like this:

class A {
public:
    A() { std::cout<<"This is default cstr."; }
    A(int i) { std::cout<<"This is int cstr. value is "<<i; }
    A(const A &a) { std::cout<<"This is copy cstr."; }
    A operator=(const A &a) { std::cout<<"This is assignment operator."; return *this;// this line is tricky }
};
int _tmain(int argc, _TCHAR* argv[]) {
    std::cout<<"line 1 "; A a1; std::cout<<std::endl;
    std::cout<<"line 2 "; A a2 = A(1); std::cout<<std::endl;
    std::cout<<"line 3 "; a1 = a2; std::cout<<std::endl;
    return 0;
}

For line 3 I got:

line 3 This is assignment operator.This is copy cstr.

But if I change return *this; to return NULL, I got:

line 3 This is assignment operator.This is int cstr. value is 0

Could someone explain what happened inside for me?

Upvotes: 1

Views: 765

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106254

The problem

line 3 This is assignment operator.This is copy cstr.

Your code's calling:

A operator=(const A &a) { std::cout<<"This is assignment operator."; return *this;

This obviously prints "This is assignment operator.", then return *this; statement sees the return type of A and creates a return value of type A doing the equivalent of A(*this); -> that calls the copy constructor, explaining this part of the output:

line 3 This is assignment operator.This is copy cstr.
                                   ^^^^^^^^^^^^^^^^^^

But if I change return *this; to return NULL, I got:

line 3 This is assignment operator.This is int cstr. value is 0

In this case:

A operator=(const A &a) { std::cout<<"This is assignment operator."; return NULL; }

You end up creating the return value of type A as per A(NULL), and as NULL is 0, that matches the A(int) constructor best, which is why you see:

line 3 This is assignment operator.This is int cstr. value is 0
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The solution

A& operator=(const A &a) { std::cout<<"This is assignment operator."; return *this; }
 ^

You normally want the assignment operator to return a reference to the *this object. That way, no additional A object is constructed as the assignment operator function returns.

Aside - why return `A&` anyway?

The reason A& is returned and not void, is that it allows further chained use of the object, as in:

a1 = a2 = a3;

Which is evaluated as:

a1.operator=(a2.operator=(a3));

Is a2.operator= returned void then there'd be no usable argument to a1.operator=().

A non-const reference supports usage like:

make_uppercase(my_string = other_string);

In some other languages, that would need to be broken into two statements. Whether you wish it was depends on whether you find it confusing, and how much you value concision.

Upvotes: 1

kfsone
kfsone

Reputation: 24269

Your code says

A operator = (const A& a)

You take a reference to an A, you modify yourself, and then you return A(*this) which invokes the copy-constructor to create a new instance and return by value.

What you probably intended was

A& operator = (const A& a)

This will then return a reference to *this rather needing to copy it into a new temporary instance.

Be aware that NULL is a macro alias for '0UL' or '0ULL' which the compiler detects as being a match for A(int). This is one of the reasons that C++11 introduced nullptr as an alternative to NULL.

Upvotes: 0

paddy
paddy

Reputation: 63501

Your operator is returning A instead of A&:

A operator=(const A &a)

So when you return NULL, you are calling the implicit constructor A(int) and passing NULL to it.

Upvotes: 1

Related Questions