Reputation: 491
I'm relatively new to C++, still trying to get a hang of the syntax. I've been taking a look at a few operator overloading examples, most recently smart pointer implementations. Here's a really generic example I'm looking at:
template < typename T > class SP
{
private:
T* pData; // Generic pointer to be stored
public:
SP(T* pValue) : pData(pValue)
{
}
~SP()
{
delete pData;
}
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
};
When overloading the dereference operator why is the type T&? Similarly, when overloading the structure dereference why is the type T*?
Upvotes: 49
Views: 76940
Reputation: 431
We are making smart pointer and our aim is to access member of class/structure using any of this T& (reference) or T* (pointer) with flexibility.
for T* operator-> ():
T* operator-> ()
{
return pData;
}
arrow operator (->) is a shorthand for (*p) and hence we return *pData which is of type T*.
here we are Overloding arrow operator so that members of T can be accessed like a pointer.
for T& operator* ():
T& operator* ()
{
return *pData;
}
* is "value at address" operator, here we are Overloding * (pointer) operator so
that members can be accessed through a reference (T&).
We can change the behavior of the operator with operator overloading but its not recommended. overloaded operator behavior should be as close as its basic functionality.
Upvotes: 0
Reputation: 10962
When overloading operaters you are free to return anything basicly (just like any other function), with the noteable exception of member of pointer ->
being somewhat special in this way.
In the example you show, a smart pointer, you aim to mimick the syntax of a pointer (pointer semantic). Then for syntax like:
*p = 2;
The indirection operator*
return a non-const reference to object and we are able to modify through operator*
. In effect, usually used for proxy type classes in the same way and it is a sort of a convention - but you could in theory return whatever.
The member of pointer operator ->
is a bit tricky. See this answer for an explanation.
Upvotes: 1
Reputation: 175
It is because pointer contains an address of a variable referencing it will give a reference (or to say a lvalue refrence) to the address it has stored.
e.g. int x; int *p; p=&x;
now x
and *p
can be used interchangeably.
if you do x =4;
or *p = 4;
both will have same result. *p
works as a reference to x
just like a normal reference int& t = x;
will work.
Next thing structure dereference operator. This operator gives you the access of member variables through a pointer to object of a class. In above example the member is T* pData;
so using this operator will give access to pData
and pData
is T*
so the return type is T*
. if pData
in above example would have been T
then the return type would have been T
.
Upvotes: 2
Reputation: 22103
The dereference operator (*
) overload works like any other operator overload. If you want to be able to modify the dereferenced value, you need to return a non-const reference. This way *sp = value
will actually modify the value pointed to by sp.pData
and not a temporary value generated by the compiler.
The structure dereference operator (->
) overload is a special case of operator overloading. The operator is actually invoked in a loop until a real pointer is returned, and then that real pointer is dereferenced. I guess this was just the only way they could think of to implement it and it turned out a bit hackish. It has some interesting properties, though. Suppose you had the following classes:
struct A {
int foo, bar;
};
struct B {
A a;
A *operator->() { return &a; }
};
struct C {
B b;
B operator->() { return b; }
};
struct D {
C c;
C operator->() { return c; }
};
If you had an object d
of type D
, calling d->bar
would first call D::operator->()
, then C::operator->()
, and then B::operator->()
, which finally returns a real pointer to struct A
, and its bar
member is dereferenced in the normal manner. Note that in the following:
struct E1 {
int foo, bar;
E1 operator->() { return *this; }
};
Calling e->bar
, where e
is of type E1
, produces an infinite loop. If you wanted to actually dereference e.bar
, you would need to do this:
struct E2 {
int foo, bar;
E2 *operator->() { return this; }
};
To summarize:
T&
because that is necessary to modify the value pointed to by pData
.T*
because this operator is a special case and that is just how it works.Upvotes: 71
Reputation: 335
The purpose of dereference operator is to dereference a pointer and returns the object reference. Hence it must return the reference. That is why it is T&.
The purpose of referring operator (->) is to return a pointer and hence T* is returned.
Upvotes: 14