Overloading '->' member access operator - c++

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.

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 ->.

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 dereferencing operators

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

assignment operator c++ NULL assignment

I am working with a class that is mostly working fine, but I am doing some functionality that I might be having a recursive function return a NULLpointer of the class type as a control, and so it might be assigning a NULL pointer to my class object so long story short:
Thing& Thing::operator=(Thing * _other){
if (_other == NULL){
*this = NULL; // compiler throws here
return *this;
}
// does other assignment work
return *this;
}
my compiler VS2010 throws that this is not an I-value. so how do I set the value to NULL, or is it even possible to set an item to NULL from inside?
EDIT: modified this to *this though for some reason now the program breaks with infinite calls to the assignment operator. no idea what is going on
You are trying to write a "nullable" class. Consider the "null" state to be one of the states an instance of Thing can be in, and don't convolute it with pointer semantics.
The general method would be to add a boolean flag to your class that keeps track of whether an instance is in null state or not. I would implement it like this:
class Thing
{
private:
bool m_null;
public:
void setnull() { m_null = true; }
bool isnull() const { return m_null; }
Thing() : m_null(true) {}
... // rest of class
};
And now the default assignment operator works fine.
You cannot directly set a value to the this pointer. Hence
this = NULL;
is semantically and syntactically wrong.
You can use exceptions to check if _other is NULL. For example:
class null_object_exception : public virtual exception {};
...
if (_other == NULL) throw null_object_exception();
To perform a NULL assignment:
Thing the_thing, other_thing;
try { the_thing = &other_thing; }
catch( const null_object_exception& e ) { the_thing = NULL; }
what are the member variables of Thing class?
if you want to show that the object is somehow without value or not intialized, you would better assign fileds 0 (for integers) and null(for pointers) etc, instead of assigning "this" which is constant.
Short answer, no, you can't assign to this in C++.
Longer answer; for your assignment operator to even be called, you'd have to have a construct like;
MyObject a;
a = NULL; // can change the content of `a` but not which object the name `a` refers to.
If you're thinking about this construct;
MyObject *a;
a = NULL;
your assignment operator won't even be called since it is an operator on the object, not the pointer. Assigning to the pointer a will work without you defining an assignment operator.
You CANNOT assign to this.
Also, you should take your arguments by const reference, so Thing& operator= (const Thing& other)
There's a great SO question in C++-faq tag about operator overloading, you can find it here