1

I have written following class which has overloaded assignment operator. As shown in example everywhere I returned *this from assignment operator.

class Sample
{
    int *p;
    int q;

public:

    Sample()
    {
        cout<<"Constructor called"<<endl;

        p = new int;
        q = 0;
    }


    Sample& Sample::operator =(const Sample &rhs)
    {
        cout<<"Assignment Operator"<<endl;

        if(this != &rhs)
        {
            delete p;

            p = new int;
            *p = *(rhs.p);
        }

        return *this;
    }

    void display()
    {

        cout<<"p = "<<p<<"     q = "<<q<<endl;
    }
};

When I call assignment operator like a = b, it goes like, a.operator=(b);.

Now I am calling a's operator function, this is already being passed with operator = then why it is required to return it from assignment operator?

Pranit Kothari
  • 9,721
  • 10
  • 61
  • 137
  • 4
    It is returned so you can do chaining. Note you don't need to `delete` and then `new` pointer `p`. – juanchopanza Oct 13 '14 at 09:48
  • @juanchopanza I got same response everywhere, but did not understand exact meaning – Pranit Kothari Oct 13 '14 at 09:53
  • `a = b;` has the return value `a`. That means you can do `a = b = c = d;`. This is what they call chaining assignments. If you return `void`m from the assignment operator `a = b` still works, but `a = b = c` does not because `a` gets a `void` and not a `Sample`. – nwp Oct 13 '14 at 09:55
  • 1
    Result type `T&` is only technically a requirement if you want to use your class as element of a standard container. However, that's a very important reason. – Cheers and hth. - Alf Oct 13 '14 at 09:57

4 Answers4

6

You have to return *this (and also by reference) if you want to support chaining of assignment. For e.g

Class A
{
};

A x,y,z,w;
x = y = z = w; //For this you are returning *this.

EDITED FOR MORE CLARIFICATION:- ( In response to your comment )

Let's suppose you're not returning anything from your assignment operator then expression will be evaluated as follows:-

x=y=z  =>   x=(y=z)

Above will result into a call to

y.operator(z)

as assignment operator is right associative. After this next call would be to

x.operator ( value returned from y=z) ).

If you don't return any value chaining would fail.

Hope I am clear

ravi
  • 10,994
  • 1
  • 18
  • 36
1

You're returning it to allow for chaining, you can't chain an assignment sequence without returning a reference to Sample, perhaps this will make it more clear:

int count = 0;

class Sample {
    int *p;
    int q;
    int m_count;
public:
    Sample() {
        m_count = count;
        cout<<"Constructor called for m_count = "<< count++ << endl;

        p = new int;
        q = 0;
    }

    Sample& operator =(const Sample &rhs) {
        cout<<"Assignment Operator (m_count " << 
                    m_count << " = m_count " << rhs.m_count << ") " <<endl;
        if(this != &rhs)
        {
            delete p; // Unnecessary
            p = new int; // Unnecessary
            *p = *(rhs.p);
        }
        return *this;
    }
};
int main() {
  Sample a;
  Sample b;
  Sample c;

  // [b = c] will return a Sample& to the "changed" b
  a = b = c;
}

Example

Counter-example with void return value:

int count = 0;
class Sample {
    int *p;
    int q;
    int m_count;
public:

    Sample() {
        m_count = count;
        cout<<"Constructor called for m_count = "<< count++ << endl;

        p = new int;
        q = 0;
    }

    void operator =(const Sample &rhs) {
        cout<<"Assignment Operator (m_count " << 
                    m_count << " = m_count " << rhs.m_count << ") " <<endl;

        if(this != &rhs) {
            delete p; // Unnecessary
            p = new int; // Unnecessary
            *p = *(rhs.p);
        }
    }
};

int main() {
  Sample a;
  Sample b;
  Sample c;

  a = b; // Valid
  a = b = c; // Not valid - error: no viable overloaded '='
}
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • A counter example with an assignment operator returning `void` would make it more clear. Also what are the parenthesis for in `a = (b = c);`? – nwp Oct 13 '14 at 09:58
  • @nwp absolutely for not reason if not making my point clear. I'll specify that – Marco A. Oct 13 '14 at 09:58
1

An assignment statement,

a = b;

Requires that b should an R-value, and a must be an L-value. When you change the assignment as:

a=foo();

The expression foo(), that is the function call to foo must result in an R-value. If foo returns void, it doesn't produce R-value (or any value). Therefore, foo is required to return a value (Via a explicit return statement(s)). That's the language mandate!

The b, in first statement may be L-value also. For example:

a = b = c;

The variable b is both L-value (for b=c), as well as R-value (for a=b). When operator= returns T&, it may act as L-value (as well as R-value). But when operator= returns const T&, it may only be R-value. Therefore, if a class returns a const reference, following wont work:

a = b = c; 

Here, c is assigned to a (in the overload itself), but b is a const (R-value only). It won't allow a=b.

Ajay
  • 18,086
  • 12
  • 59
  • 105
  • 1
    You're incorrect about the L-value and R-value categorisations. The names started like this, but they have a very different meaning now. It is perfectly possible to assign to an rvalue (of class type), and if the parameter of the assignment is of reference type, an lvalue-to-rvalue conversion never needs to happen on the right-hand side argument. – Angew is no longer proud of SO Oct 13 '14 at 10:21
  • @Angew, you are right. We are in C++14 era, but conceptually L-value and R-value are what they are! – Ajay Oct 13 '14 at 10:23
  • In C++ (since C++11), *lvalues* and *rvalues* are what 3.10 [basic.lval] defines them to be. I consider it quite confusing to use a term for something else than the term's defined meaning. – Angew is no longer proud of SO Oct 13 '14 at 10:28
  • @Angew, I respect your knowledge, and you are free to edit the post. :) – Ajay Oct 13 '14 at 10:46
0

Its mainly to support assignment chaining.

Sample A,B,C;
A=B=C;

You can have a look into the existing questions:

Why should the assignment operator return a reference to the object?

Why must the copy assignment operator return a reference/const reference?

Community
  • 1
  • 1
iampranabroy
  • 1,716
  • 1
  • 15
  • 11