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.
*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 toT
,” 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.
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.