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:
- When overloading the dereference operator, the type should be T&because that is necessary to modify the value pointed to bypData.
- When overloading the structure dereference, the type should be T*because this operator is a special case and that is just how it works.