简体   繁体   中英

Why does “return *this” return a reference?

In my C++ class they were discussing how to create an assignment operator. At the end of the assignment was the line "return *this," which they said returned a reference to the object that "this" points to. Why does it return a reference? If "this" is being dereferenced, shouldn't it just return the object?

A function returns a reference if its declaration (ie its signature) tells so.

So (assuming a class Foo ) if a function is declarated

 Foo fun();

then it returns a value (with copying, etc..)

But if it is declared as

 Foo& fun();

or as

 const Foo& fun();

a reference is returned.

The statement return *this; don't define by itself if a reference or a value is returned.

It returns the current instance of the type MyClass you are in. It's returned as reference because the assignment operator was explicitly told to return a reference.

MyClass& operator = (MyClass& other)  { return *this; }

Note the & after MyClass as the return value. A reference is returned. Unless the & weren't there right before operator , the instance would be returned by value.

The expression *this

At the end of the assignment was the line "return *this," which they said returned a reference to the object that "this" points to

They were wrong.

Why does it return a reference?

It doesn't.

If "this" is being dereferenced, shouldn't it just return the object?

Yes!

Dereferencing a pointer yields an lvalue . That means that the result of *this is the actual object that this points to. It's not a reference, but it's not a copy either.

[C++11: 5.3.1/1]: The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. If the type of the expression is “pointer to T ,” the type of the result is “ T .” [..]

It can be hard to conceptualise, since you can never do this yourself in code; it's just a feature of the * operator for native pointers, and has been since C.


Returning from operator=

Because you can't do it yourself, conventionally you'd bind that lvalue expression to a reference in order to use it in different contexts. For example, the expression *this in return *this gets bound to the return type of the function that you're returning from; in this case, an assignment operator.

Now, we could have the assignment operator return by value in which case an object copy would be made from the lvalue that comes from *this ; however, for an assignment operator we usually return by reference so that we avoid an almost-certainly needless copy, and can perform chaining :

Type a, b, c;
c = b = a;

It's a convention with benefits, and no downsides. Can you think of a situation when you'd want op= to return by value?

Every dereferenced pointer is a reference to its pointee, else you'd 'loose' the pointee you're pointing to.

Invoke method twice on the same object, using a pointer and a reference:

MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass& objRef = *objPtr;
objRef.doSomething();

Invoke method on distinct objects; original and copy:

MyClass* objPtr = .... ;
objPtr->doSomething();
MyClass objCopy = *objPtr; //here, the reference is passed to the (implicit or implemented) copy constructor if possible, else a compile time error occurs.
objCopy.doSomething();

That means, if you return a reference from an operator method which has MyClass (rvalue) instead of MyClass& (lvalue) as return type, a copy of *this (MyClass&) is created by reference (leaving aside return value optimizations and rvalue references). This is useful for non modifying const methods such as + and - which have a new value as result while leaving the object on which this method was invoked unmodified.

Operators like += and your assignment operator modify the object inplace by convention and should therefore return a reference to allow expressions like primitive types support it, since a temporary copy may vanish and cause unexpected results:

Consider this expression:

int i = 4;
int r = (i += 3) <<= 2;

The result r is 28 (added and shifted inplace). What is the value of i? 28 too, what else.

But what if hypothetically int::operator+= would return a copy of itself instead of a reference to itself?

The result r would be 28 too.

But the value of i? It would be 7, since the inplace left shift was applied to a temporary int returned from the addition which gets assigned to r after that.

Continuing the assumption, the error may have the same effect (except for the value in i) as this expression:

int r = (i + 3) <<= 2;

But luckily, the compiler will complain, that he doesn't have an lvalue reference from (i + 3) to do the shift/assignment operation.

But play with this:

class Int
{
private:
    int val;
public:
    Int(int val) :
            val(val)
    {
    }

    Int operator+(const Int& other)const
    {
        return val + other.val;
    }
    Int operator+(int prim)const
    {
        return val + prim;
    }

    Int& operator+=(const Int& other)
    {
        val += other.val;
        return *this;
    }
    //Error here, Int& would be correct
    Int operator+=(int prim)
    {
        val += prim;
        return *this;
    }

    Int operator<<(const Int& other)const
    {
        return val << other.val;
    }
    Int operator<<(int prim)const
    {
        return val << prim;
    }

    Int& operator<<=(const Int& other)
    {
        val <<= other.val;
        return *this;
    }
    Int& operator<<=(int prim)
    {
        val <<= prim;
        return *this;
    }

    operator int()const{
        return val;
    }
};

int main()
{
    Int i = 4;
    Int r = (i += 3) <<= 2;

    cout << i;
    return 0;
}

In C++ the * always means a value, in fact you can look to en English interpretation for these operators as follows:

& : the address of

* : the value of

So when you say &x it means "the address of x" and when you say *x it means "the value that x points to". So *this will always return a value.

Just be sure that the function itself that the hosts the returning is not a reference function. Please remember that in C++ you can create functions with the & or the * operators as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM