Question

I have conflict in below codes.

#include <iostream>
using std::cout;
using std::endl;

class TestApp {
public:

    TestApp(int _x = 9) {
        cout << "default constructor\n";
    }

    TestApp(const TestApp &app) {
        cout << "Copy constructor\n";
    }

    ~TestApp() {
        cout << "destructor\n";
    }

    void setX(int _x) {
    }

    const TestApp &operator=(TestApp &obj) {
        cout << "= operator\n";
        return *this;
    }

    void setX(int _x) {
        cout << "Inside setX\n";
    }
};

int main() {
    TestApp app1;
    TestApp app2;
    TestApp app3;
    (app1 = app2) = app3; // 1
    app1 = app2 = app3; // 2
    app1.setX(3)
    return 0;
}

I got this error: for line 1 main.cpp:38: error: passing ‘const TestApp’ as ‘this’ argument of ‘const TestApp& TestApp::operator=(TestApp&)’ discards qualifiers However I can use app1.setX(3);

main.cpp:38: error: no match for ‘operator=’ in ‘app1 = app2.TestApp::operator=(((TestApp&)(& app3)))’
main.cpp:28: note: candidates are: const TestApp& TestApp::operator=(TestApp&)

and to make it working I should make operator= like:

TestApp &operator=(const TestApp &obj) {
        cout << "= operator\n";
        return *this;
} // works for 1

TestApp &operator=(TestApp &obj) {
        cout << "= operator\n";
        return *this;
} // works for 2

why if I remove const keyword it works? and after line 1 app1 object is not constant.

Was it helpful?

Solution

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.

OTHER TIPS

The correct way to provide an assignment operator is to declare it as follows:

TestApp &operator=(const TestApp &obj) {
    cout << "= operator\n";
    return *this;
}

Note that there is only one const in front of the right hand side operand, the operator itself and its return value are not declared const.

It is wrong to declare the operator const because the assignment operator is meant to modify the this object.

And it unnecessarily constrains the use of the operator to return a const reference, because the caller already provided you with a non-const reference. Consequently, the caller already has non-const access to the object, so returning a const reference unnecessarily stops him from reusing the return value in a non-const context

This is what happens when you do the double assignment app1 = app2 = app3;: It is evaluated as app1 = (app2 = app3);, so the return value of one assignment is passed as the right hand side parameter to the next assignment. The non-const reference returned by the first assignment can implicitly be converted to a const reference, so this works fine.

If your compiler complains about your line 2 with the declaration given above, then your compiler is to blame. I have checked the following code with gcc 4.7.2, and it works fine:

class Foo {
    public:
        Foo() {};
        Foo(const Foo& other) {}
        Foo& operator=(const Foo& other) { return *this; }
};

int main() {
    Foo foo1, foo2, foo3;
    (foo1 = foo2) = foo3;
    foo1 = foo2 = foo3;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top