Here is my code example:
class X
{
public:
void f() {}
};
class Y : public X
{
public:
X& operator->() { return *this; }
void f() {}
};
int main()
{
Y t;
t.operator->().f(); // OK
t->f(); // error C2819: type 'X' does not have an overloaded member 'operator ->'
// error C2232: '->Y::f' : left operand has 'class' type, use '.'
}
Why the compiler is trying to "move the responsibility" for operator-> from Y to X? When I implement X::op-> then I cannot return X there - compile error says "infinite recursion" while returning some Z from X::op-> again says that Z doesn't have operator->, thus going higher and higher in hierarchy.
Can anyone explain this interesting behavior? :)
The problem is that operator -> is supposed to return a pointer, not a reference. The idea is that operator -> should return a pointer to the real object that should have the pointer applied to it. For example, for a class with an overloaded operator ->, the code
myClass->myValue;
translates into
(myClass.operator-> ())->myValue;
The problem with your code is that operator -> returns a reference, so writing
myClass.operator->().f();
is perfectly legal because you're explicitly invoking the operator, but writing
myClass->f();
is illegal, because the compiler is trying to expand it to
myClass.operator->()->f();
and the return type of operator-> isn't a pointer.
To fix this, change your code so that you return a pointer in operator ->. If you want to overload an operator to return a reference, overload operator *; pointer dereferences should indeed produce references.
Because that's how overloaded -> works in C++.
When you use overloaded ->, expression a->b is translated into a.operator->()->b. This means that your overloaded operator -> must return something that will itself support another application of operator ->. For this reason a single invocation of overloaded -> might turn into a long chain of invocations of overloaded ->s until it eventually reaches an application of built-in ->, which ends the chain.
In your case you need to return X* from your overloaded ->, not X&.
The syntax is wrong, should be:
T->T2
T2* T::operator ->();
Look at wikipedia's article: Operators in C and C++
If you want to overload, you must use the right syntax for the overloaded operator
You probably want:
class Y : public X
{
public:
X* operator->() { return this; }
void f() {}
};
Related
It seems that Clang's UO_AddrOf unary operator is sensitive to the overloading of operator&.
For example, if we have
class notapointer {};
struct Bar
{
inline notapointer operator&()
{
return notapointer();
}
};
and E is a clang expression containing an instance of Bar, then
Expr* AddrOfE = Sema::BuildUnaryOp(0, loc, UO_AddrOf, E).get();
will return an expression of a notapointer instance instead of the address the object.
Is there a means to retrieve the actual address instead of following the operator& overload?
In a way, it behave like std::addressof.
What an operator is overloaded here?
operator T * ()
I know that the operator method has the following structure:
type operator operator-symbol ( parameter-list )
Assume we have the following code
template<typename T> class SmartPtr
{
public:
SmartPtr(T* data): member(data) {}
T* member;
T& operator * () { return *member; } //usage: *TObj
T*& operator () () { return member; } //usage: TObj()
operator T * () { return member; } //usage: ???
};
No compilation errors if you try it on the ideone. So what is going on here?
ADD: Am I right that static_cast<T*>(TObj) makes a call of the operator T *? I've tried it here.
That's a conversion operator, which allows the class to be converted to T*. Usage:
T * p = TObj;
It's probably a bad idea for a smart pointer to provide this, as it makes it easy to accidentally get a non-smart pointer. Standard smart pointers provide explicit conversion via a get() function instead, to prevent accidental conversions.
This operator is invoked when a SmartPtr object appears in an expression, but the compiler has no functions available to resolve the usage made thereof: if it's legal to use a T* where the SmartPtr appears, the operator T*() function is called to generate one. This means my_smartptr->my_T_member can work, as can f(T*); f(my_smart_ptr_to_T);. Similarly, iostreams have an operator bool() in C++11 (operator void*() in C++03 for reasons too tedious to bother with). It's kind of the opposite of an implicit constructor from a single parameter, where should the compiler not find a valid match using the parameter, it may try to construct an object using that parameter to use instead.
operator T * () { return member; }
it is a so-called conversion operator. It converts an object of type SmartPtr to type T *. Moreover it is an implicit conversion opertaor. So when the compiler awaits an object of type T * you can use instead an object of type SmartPtr.
You could make this conversion operator explicit if you would add keyword explicit. For example
explicit operator T * () { return member; }
I'm sure that some of my questions may have been asked before, so please let me know :).
First, an example:
#include <iostream>
struct A
{
typedef void (A::*funcptr)();
operator funcptr() {
std::cout << "funcptr" << std::endl;
}
};
int main()
{
A a;
if (a) {}
}
At if(a), operator funcptr() is called, but I'm not exactly sure what is happening here. I'm assuming the compiler looks for a conversion from an A to bool and finds operator functptr which is okay, but how does conversion work with pointers to member functions?
Also, if I changed operator funcptr() to operator int A::*() it would also work, but operator void A::* doesn't (I get cannot declare pointer to 'void' member), what is the rule I am missing there? (My questions are mostly related to trying to fully understand the safe bool idiom)
Also, if I declared operator bool() it would take precedence, so what are there rules for precedence?
To answer your second question, if you use
operator int A::*() { }
then you are creating a conversion operator which returns a pointer to an int member. Not a pointer to a member function. Since you can't have members of type void,
operator void A::*() { }
isn't valid.
I dont understand, why is the aaa operator called in the 2nd last line?
#include <iostream>
class MyClass
{
private:
typedef void (MyClass::*aaa)() const;
void ThisTypeDoesNotSupportComparisons() const {}
public:
operator aaa() const { return (true) ? &MyClass::ThisTypeDoesNotSupportComparisons : 0; }
};
int main()
{
MyClass a;
MyClass b;
if(a && b) {}
}
The compiler searches for the best match for (a && b).
Because the class doesn't have an operator that turns MyClass to a boolean, it searches for the best cast.
operator aaa() const is a cast to an aaa type pointer. Pointers can be evaluated in an if sentence.
Overloading typecasts
Conversion Functions (C++)
Your variables are used in an expression. The type itself does not have an operator&& defined for it, but it is convertible to a type (a pointer) that can be used in the expression. So the conversion operator is called.
It looks like a type cast operator. Oops, never mind, misread 'why is this operator called' for 'what is this operator called'
Ok, I tested your code and examined it some more. So operator aaa is a type cast to type aaa. Type aaa is a pointer to a member function of type void func(). ThisTypeDoesNotSupportComparisons is a function of type aaa. operator aaa gets called and returns the pointer to function.
I think it is called because the if allows to use pointers to functions as well. You can test if a pointer is NULL or not, and this is the closest the compiler can find, so if calls the operator aaa and tests if the pointer returned is zero.
class Test
{
public:
operator Test * () { return NULL; };
};
int main()
{
Test test;
if (test == NULL)
printf("Wtf happened here?\n");
return 0;
}
How is it that this code compiles? How did Test get a comparison operator? Is there some implicit casting going around? What does that overloaded operator even mean (and do)?
The overloaded operator adds a conversion from Test to Test *. Since there is no comparision operator defined that takes Test and NULL as arguments, any conversion operators that exists are tried. operator Test * returns a type which is comparable with NULL, so it is used.
Yes, you've added an implicit conversion to T*, so the compiler will use it to compare against NULL.
A few other things to note:
NULL is shorthand for 0, so this means that comparison against 0 will be allowed. (This isn't true for other integer values, however. 0 is special.)
Your type also can be implicitly used in boolean contexts. That is, this is legal:
Test test;
if (test)
{
// ...
}
C++0x allows you to specify an explicit keyword for conversion operators to disallow this sort of thing.
Implicit conversion to pointer types is often pretty dubious. In addition to the pitfalls of the conversion happening in unexpected cases, it can allow dangerous situations if the object owns the returned pointer. For example, consider a string class that allowed implicit conversion to const char*:
BadString ReturnAString();
int main()
{
const char* s = ReturnAString();
// Uh-oh. s is now pointing to freed memory.
// ...
}
+1 for Baffe's response. If you're looking to somehow expose some instance of a wrapped object via * then perhaps you should overload -> instead of overloading *.
class Bar
{
public:
void Baz() { ... }
}
class Foo
{
private:
Bar* _bar;
public:
Bar* operator -> () { return _bar; }
}
// call like this:
Foo f;
f->Baz();
Just a thought.
You have not defined your own comparison thus he compiler has done one for you. you have however tried to overload the dereference operator... which I can't see why.
you want to define your operator== function
read this