Overloading dereferencing operators - c++

noGiven a private Member pData
private:
T* pData; // Generic pointer to be stored
Below is the overloaded implementation of * and ->
T& operator* ()
{
return *pData;
}
T* operator-> ()
{
return pData;
}
We call the same from the main as shown below:
void main(){
SP<PERSON> p(new Person("Scott", 25));
p->Display();
}
I cannot understand how -> and "*" operator overloading will work here?
or to be more clear how p->Display(); will be interpreted?

The -> operator is special. When it returns an object, it is automatically applied again. If it returns another object it is also applied again, until finally a plain pointer is returned. This is called chaining, the plain pointer is finally dereferenced and the chain stops.
p->Display() is therefore interpreted like this:
p->Display(); // Compiler sees this
T* tmp = p.operator->(); // First applied operator-> (the one you provided)
tmp->Display(); // since T* is a pointer itself, operator-> (the built-in one for pointers) is applied

Related

overloading the operator ->

I was looking at overloading the -> operator. I came up with the following simple example:
struct foo
{
int p = 12;
};
struct A
{
foo* f;
A()
{
this->f = new foo();
}
foo* operator-> ()
{
return f;
}
};
int main()
{
A a;
std::cout << a->p; //output 12
}
Although this example works, yet I am hoping if someone could tell me why it works.
I was thinking that it should work like this
std::cout << a->->p; //The first arrow returns the pointer
//the second arrow dereferences it
but here it seems like a single arrow not only returns the pointer but it also dereferences it. Is this a special case in C++?
Yes, this is by-design, operator-> will be called recursively on the return value; then we can use such class (so-called smart pointers) in the same way as raw pointers.
If a user-defined operator-> is provided, the operator-> is called again on the value that it returns, recursively, until an operator-> is reached that returns a plain pointer. After that, built-in semantics are applied to that pointer.

Syntax using the return value from an overloaded -> operator

So I think I might be overthinking this but I wanted to know if someone could clarify why the following statement works in the given code
f->hello();
This is the code
struct bar
{
void hello()
{
std::cout << "Hello World";
}
};
struct foo
{
bar* f;
foo() {
f = new bar();
}
~foo() {
delete f;
}
bar* operator->() {
return f;
}
};
int main()
{
foo f;
f->hello(); //Works
}
Since the following code from above returns a pointer
bar* operator->() {
return f;
}
should'nt
f->hello(); actually be f->->hello();
why does f->hello() work and f->->hello() fails ?
The reason i am thinking that f->->hello() should work is because
f->ptrReturned->hello();
If we overload the -> operator are we required to return a ptr type ? Form what I have tried it seems returning an object type is not allowed
Your understanding is correct basically, but ->-> is not valid syntax. You can use the overloaded operator-> like
f.operator->()->hello();
//^^^^^^^^^^^^ return the pointer
// ^^^^^^^^^ call hello() on the returned pointer
f->hello() is treated as the same of f.operator->()->hello(); that makes the usage of class with overloaded operator-> (e.g. smart pointers) consistent with built-in pointers. The usage would be more natural, and could be used with raw pointers in more general context like templates.
And,
If we overload the -> operator are we required to return a ptr type ?
There're some restrictions:
The overload of operator -> must either return a raw pointer, or return an object (by reference or by value) for which operator -> is in turn overloaded.
Apparently, that's just how an overloaded operator-> works. The part before the -> (not including the operator itself) gets replaced with the return value of the overloaded operator. For example, std::unique_ptr::operator-> returns a pointer, which then gets dereferenced by the ->.

Overloading '->' member access operator

While overloading operator* we do as follows:
T & operator * () { return *ptr; }
That means if I have:
SmartPtr<int> obj(new int());
*Obj = 20;
Cout << *obj;
Then the *obj part is replaced by *ptr so its as good as:
*Ptr=20
cout<<*ptr
Now while overloading operator-> we do the following:
T * operator -> () { return ptr; }
And it can be accessed as:
Obj->myfun();
What I don't understand here is after evaluating the obj-> is replaced by ptr so it should look as follows:
ptrmyfun(); // and this is syntax error
Where am I going wrong?
C++ does not work like search/replace in a text editor. "obj1->" is not replaced by ptr verbatim, as if this was a line of text in a text file.
With:
Obj->myfun();
The fact that the -> operator invokes a custom operator that returns ptr:
T * operator -> () { return ptr; }
That doesn't mean that the original statement somehow becomes
ptrmyfun();
As if "Obj->" was replaced by "ptr". C++ simply does not work this way, like search/replace in a text editor.
The -> operator results in the custom operator->() getting invoked. That part, of how you understand operator overloading works, is correct.
But what happens is that, simply, the return value from the operator->() becomes the actual pointer value to which the actual pointer dereference gets applied to.
So this becomes, essentially:
ptr->myfun();
That's all.

how operator overloading in the below code work?

Consider this code
// Example program
#include <iostream>
#include <string>
class SmartPtr{
int *ptr;
public:
explicit SmartPtr(int *ptr=0){
ptr = new int;
}
~SmartPtr(){
std::cout<<"Dest is called"<<std::endl;}
int& operator *() //overloaded operator for dereferencing
{
std::cout<<"(*) is called .."<<std::endl;
return *ptr;
}
int * operator ->() //overloaded operator for referencing
{
std::cout<<"(*) is called .."<<std::endl;
return ptr;
}
};
int main()
{
SmartPtr p(new int());
*p = 20; //overloaded operator * called
std::cout<<*p<<std::endl; // Overloaded operator * called
// End of program
//Destructor called
}
here i have overloaded operators * and & , i want to understand why that type of function signature based on the comments i have mentioned in main function .
If someone can explain how it works ?
PS : I am new to C++ and explaination i am asking is trivial {i know :)}
This is the way smart pointers are constructed.
They are wrappers of pointers of any class and they control the deallocation of these objects by automatically calling their destructor when the smart pointer goes out of scope.
In order to expose the interface of the wrapped class, they must overload * and -> operators and return the wrapped object's pointer.
In C++ you can define functions as behavior of operators on your types. That is exactly, what happens here.
int& operator * () declares the function, that is used for the unary * operator. The result of that operator then is a reference to an int.
int* operator -> ()then declares the function for ->. This one is a bit special, since it will be used on the return value again, until there is a pointer, which will be used to apply the standard behavior of ->.
After you have declared these operators, the compiler will accept them on any object of your type. You can then write *myObj go get the result of the operator * () function.
This feature gives you the power to extend the language in parts. Note, that the return types can be chosen as needed. If you look at advanced libraries, that implement domain specific languages, you'll find a lot of that. Boost::spirit is an extreme example of that.

overloading "new" operator

While I was defining the working of an overloaded new operator declared in a class,
I came across following confusion....
HERE ,the return type of the function is 'void',yet I
have to introduce a return statement.....otherwise my program crashes....why so?
What is meant by "void *p"
void *myclass::operator new(size_t size)
{
void *p;
p=malloc(size);
cout<<"IN overloaded new";
if(!p)
{
bad_alloc ba;
throw ba;
}
return p;
}
to the point clarifications are appreciated.
The return type of the function is not void, its a void* (void pointer). A void pointer is a generic pointer which can point to anything, but it cannot be dereferenced - you have to cast it to another type prior to dereferencing it.
If you don't return the void *, then you're not returning the pointer to the memory you allocated, and the users code will fail.
void* is an untyped pointer. It's a pointer that can point to anything. Note that the return type of this function is not void but void*. It's supposed to return a pointer to the memory that was allocated.
Simple demonstration of overloaded new
void* operator new(size_t num)
{
return malloc(num);
}
The return type of the overloaded new must be void*. It is expected to return a pointer to the beginning of the block of memory allocated.ie Here it is returning void * and not void(which means doesnt return anything) .