user3273777
user3273777

Reputation: 491

C++ overloading dereference operators

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

Answers (5)

Pankaj
Pankaj

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

darune
darune

Reputation: 10962

Overloaded operators are just functions

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

luck
luck

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

Matt
Matt

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:

  1. When overloading the dereference operator, the type should be T& because that is necessary to modify the value pointed to by pData.
  2. When overloading the structure dereference, the type should be T* because this operator is a special case and that is just how it works.

Upvotes: 71

Saminathan S
Saminathan S

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

Related Questions