2
#include <iostream>
using namespace std;
class A
{
public:
    A(int a)
    {
        length = a;
    }
    ~A(){}

    friend A operator +(A& var1, A& var2);
    A& operator=(A &other);

    int length;
};

A operator +(A& var1, A& var2)
{
    return A(var1.length + var2.length);
}

A& A::operator=(A &other)
{
    length = other.length;
    return *this;
}


int main()
{
    A a(1);
    A b(2);
    A c(3);
    c = a;   // work
    c = a + b;  // does not work
    cout << c.length ;
    return 0;
}

In main(), c = a is successfully compiled but "c = a + b" is not. However, in A& A::operator=(A &other), if I change (A &other) into (A other) then it works. Can anyone help me with this case?

2 Answers 2

8

The simplest fix is to make your assignment overload take it's parameter by const reference.

Then the temporary returned by a + b can be used with it.

A& A::operator=(A const & other)
{
    length = other.length;
    return *this;
}

You'll probably want to do the same thing with your operator+ so that c = a + a + a; will work as well.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for your answer. However, I still don't understand why your way works. As I know, a + b will return an object A, so what is the difference between not using "const" and using "const" in A& A::operator=(A const & other)? By the way, I've never seen "const" being used after the class name like this. Can your explain it for me? Thank you.
@MrCold: There's no difference between A const& and const A&. Similarly, A const* is the same as const A*. But A* const is a different beast completely.
@MrCold the difference is that C++ doesn't let you bind a non-const reference to a temporary such as the A returned by a + b. Instead, if operator='s argument is a const reference it is allowed to bind. The reason C++ prevents the non-const reference binding is just that it makes it easy for code to modify a value that's about to be destroyed - the changed state isn't then around to do anything with, so it's considered a "code smell" and usually indicates a programming mistake, though occasionally it'd be useful.
A &A::operator=(A other) has the advantage that it serves as copy-assignment and move-assignment in one.
@MattMcNabb And the disadvantage that it isn't that great an implementation for either.
|
-1

The problem is that operator + returns a temporary object

friend A operator +(A& var1, A& var2);

But a temporary object may not be bound to a non-const reference that is the type of the parameter of the assignment operator.

A& operator=(A &other);

So the compiler issues an error for statement

c = a + b;

You have three possibility.

The first one os to declare the parameter of the copy assignment operator as constant reference

A& operator=(const A &other);

It is the simplest approach.

The second one is to declare a move assignment operator instead of the copy assignment operator. In this case you explicitly need to define also a copy or move constructor. In this case instead of

c = a;

you have to write

c = std::move( a );   // work

For example

#include <iostream>
using namespace std;
class A
{
public:
    A(int a)
    {
        length = a;
    }
    ~A(){}

    friend A operator +(A& var1, A& var2);
    A& operator=(A &&other);
    A( A && ) = default;
    int length;
};

A operator +(A& var1, A& var2)
{
    return A(var1.length + var2.length);
}
A& A::operator=(A &&other)
{
    length = other.length;
    return *this;
}

int main()
{
    A a(1);
    A b(2);
    A c(3);
    c = std::move( a );   // work
    c = a + b;  // does not work
    cout << c.length ;
    return 0;
}

And at last you could have the both operators simultaneously. For example

#include <iostream>
using namespace std;
class A
{
public:
    A(int a)
    {
        length = a;
    }
    ~A(){}

    friend A operator +(A& var1, A& var2);
    A& operator=(const A &other);
    A& operator=(A &&other);
    A( const A & ) = default;
    int length;
};

A operator +(A& var1, A& var2)
{
    return A(var1.length + var2.length);
}

A& A::operator=(const A &other)
{
    length = other.length;
    return *this;
}

A& A::operator=(A &&other)
{
    length = other.length;
    return *this;
}

int main()
{
    A a(1);
    A b(2);
    A c(3);
    c = a;   // work
    c = a + b;  // does not work
    cout << c.length ;
    return 0;
}

In this case in statement

    c = a;   // work

there will be called the copy assignment operator and in statement

    c = a + b;  // does not work

there will be called the move assignment operator.

Of course you also may have the copy constructor and move constructor simultaneously the same way as the copy assignment operator and the move assignment operator. For your class you could all them define as defaulted. For example

#include <iostream>
using namespace std;
class A
{
public:
    A(int a)
    {
        length = a;
    }
    ~A(){}

    friend A operator +(A& var1, A& var2);
    A& operator=(const A &other) = default;
    A& operator=(A &&other) = default;
    A( const A & ) = default;
    A( A && ) = default;
    int length;
};

A operator +(A& var1, A& var2)
{
    return A(var1.length + var2.length);
}


int main()
{
    A a(1);
    A b(2);
    A c(3);
    c = a;   // work
    c = a + b;  // does not work
    cout << c.length ;
    return 0;
}

2 Comments

You're making it unnecessarily complicated by bringing "moving" into the picture. The OPs just trying to create a simple value type with no pointers - move isn't useful and may hide the problem but isn't a good fix.
@Tony D In my opinion you are entirely wrong I am providing a general observation of the problem. It is always better than some one solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.