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.
Related
This is an overloaded operator contained in a class:
inline operator const FOO() const { return _obj_of_type_FOO; }
I cannot for the life of me understand:
How I would invoke this operator?
What would be its return value?
[Secondary] Whether making it inline affects anything apart from efficiency?
That expression looks like a declaration of a conversion operator if Foo is a type and it is inside a class. The second const (the one closer to the opening curly bracket) means that the conversion can be called on const instances. Let us say the class is C. You can think of a conversion operator as a constructor outside a class. For example, you can't add constructors to the class std::string, but you can add a conversion operator to std::string to your classes. The result is that you can construct std::string from your class instance.
1) How to invoke the conversion operator: by constructing a value of type Foo from a C, for example:
Foo foo = c (where c is an instance of C, the class that declares the conversion operator). Mind you that the invocation of the conversion can happen implicitly. If you have, for example, void funOnFoo(Foo v); and an instace c of C, this might implicitly call operator const Foo: funOnFoo(c). Whether this actually does, depends on the usual things: Whether there are other overloads of funOnFoo, other conversions for C, etc.
2) The return value is const Foo
3) inline means the same thing as for any function, in particular, does not affect overload resolution
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.
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() {}
};
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
Let say I have a object. I'm assigning that to an integer.
MyClass obj1 = 100;//Not valid
Let's say, I have a parameterized constructor which accepts an integer.
MyClass(int Num)
{
// .. do whatever..
}
MyClass obj1 = 100;//Now, its valid
Likewise on any circumstance, does the vice-versa becomes valid?!.
eg) int Number = obj1;//Is it VALID or can be made valid by some tweeks
EDIT:
I found this to be possible using Conversion Functions.
Conversion functions are often called "cast operators" because they (along with constructors) are the functions called when a cast is used.
Conversion functions use the following syntax:
operator conversion-type-name ()
eg) Many have explained it neatly below
Yes, provided that the object is implicitly convertible to an int, either directly or through an intermediate object.
E.g. If your class have a conversion operator int it would work:
MyClass
{
public:
operator int() const { return 200; }
};
C++ constructors that have just one parameter automatically perform implicit type conversion. This is why conversion from int to MyClass works. To create conversion from MyClass to int you have to define operator int() inside MyClass.
Yes you can, using user defined conversions.
In your MyClass, define operator int()
So
class MyClass
{
int myVal;
public:
operator int() { return myVal;}
}
Yes, you need to add a conversion operator to MyClass
operator int();
MyClass is not an integer therefore you can't do int Number = obj1;
You should have a method or operator(stated by others) in MyClass that returns an int. (int number = obj1.GetNum();)