You may not assign constant objects. For example consider this simple code
const int x = 10;
x = 20;
The compiler will issue an error for the second statement because x is a constant object and may not be assigned.
The same is valid for statement
(app1 = app2) = app3;
here expression (app1 = app2)
returns constant reference that may not be assigned,
A constant reference does not mean that the object itself that it refers to is constant. Consider the following example
int x = 10;
const int &rx = x;
x = 20;
rx = 30;
Though rx is defined as constant reference you may change the object x itself. You may not use the reference to assign object x, so the compiler will issue an error for the last statement.
We use constant references very often in parameter declarations of functions that to prevent changing of objects they refer to inside the functions. For example
void f( const int &x )
{
x = 20; // compilation error
}
int x = 10;
f( x );
So defining a constant reference to a non-constant object does not makes the object itself constant. It only prevents to change the object using this reference.
And you need to define only one copy assignment operator
TestApp &operator=(const TestApp &obj) {
cout << "= operator\n";
return *this;
} // works for 1
There is no any need to define the copy assignment operator as
TestApp &operator=(TestApp &obj) {
cout << "= operator\n";
return *this;
} // works for 2
if you are not going to change the right operand. So it is better to define it as a constant reference const TestApp &obj
Of course you may have these two operators together but there is no any sense to have the second operator.
On the other hand you may not have only the second operator. In this case you will be unable to use constant objects that assign them to other objects.