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.