Prev
C++ VC ATL STL Adapter Experts Index
Headers
Your browser does not support iframes.
Re: Function pointer help
From:
Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
Newsgroups:
comp.lang.c++
Date:
Fri, 24 Oct 2008 02:19:58 -0700 (PDT)
Message-ID:
<e935a127-53da-4fd4-8ca5-d0c0b4751575@v53g2000hsa.googlegroups.com>
On Oct 24, 8:51 am, James Kanze <james.ka...@gmail.com> wrote:
On Oct 24, 3:39 am, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
ghula...@gmail.com wrote:
On Oct 23, 4:15 pm, "ghula...@gmail.com" <ghula...@gmail.com> wrote:
I am having trouble implementing some function pointer
stuff in c++
An object can register itself for many events
void addEventListener(CFObject *target, CFEventHandler
callback, uint8_t event);
so I declared a function pointer like
typedef void (CFObject::*CFEventHandler)(CFEvent *theEvent);
So when I register a handler
plane->addEventListener((CFObject *)gun, &MachineGun::handleEvent, 0=
);
Just curious, but: what is the type of gun, and why did you cast
it?
MachineGun's class contains
void handleEvent(CFEvent *theEvent);
I am getting the following error:
error: no matching function for call to
'Airplane::addEventListener(CFObject*, void (MachineGun::*)(CFEvent*=
),
uint8_t&)'/Users/ghulands/Desktop/arduino-0012/hardware/libraries/
CoreFoundation/CFApplication.h:42: note: candidates are: void
CFApplication::addEventListener(CFObject*, void (CFObject::*)
(CFEvent*), uint8_t)
MachineGun is a subclass (not a direct one) of CFObject.
If I put an event handler on CFObject it compiles fine. I
don't want to have to put it in there as a virtual method
as it will break the design.
Is there a way for the function pointer definition to be
defined in that it can also accept subclasses of the type?
Found the solution: static_cast<>
plane->addEventListener(gun,
static_cast<CFEventHandler>(&MachineGun::handleEvent), 0);
You should be aware that this is dangerous. You're basically
telling the compiler to shut up, claiming that you know what
you're doing. In fact converting (and using) the pointer to
member of derived when a pointer to member of base is expected
is wrought with peril. What if the object for which you're
going to use your handler is not of the type 'MachineGun'?
And inside the handler you will pretend that the 'this'
pointer is a pointer to 'MachineGun', which is not right.
Undefined behaviour ensues.
Virtual functions are there for a reason, you know...
I agree. It's an example of very poor design. On the other
hand, it seems to be an established idiom in some GUI circles;
I've seen it required by more than one framework.
wxWidgets is one example.
On the whole: a much better design would be to define an
abstract base class for the EventHandler, with a pure virtual
function for the notification, and pass a pointer to it. In
many cases, his actual implementation class can just derive from
this abstract base class (in addition to any other classes it
may derive from), and implement the function directly.
They argue that if there are hundreds of events there should be
hundreds of virtual functions. Which leads to relatively large virtual
tables for every derived class.
Otherwise, it's not too hard to define a forwarding class---you
could even create a template class which you just have to
instantiate---and use it.
If you really insist on using the above pattern, it should be
done by means of a template member function, e.g.:
template< typename T >
void MyClass::addEventHandler(
T* obj,
void (T:* pmf)( CFEvent* ),
uint8_t ) ;
(You can safely do the static_cast<> bit inside this function,
and even call a private member function, virtual or not, with
the results of the cast. But you've ensured type safety at the
user interface level, at least.)
IMHO, using member function pointers for callbacks is always a design
mistake because it requires casting member function pointers, which is
not portable. And looks wrong because there are easier ways to achieve
the desired effect of calling back a member function of an object.
It is trivial to make it right in a 100% portable way using C-style
callbacks, i.e. function pointer + void* pointer. Such callbacks can
be bound to regular functions as well as to member functions. The only
cast required is absolutely safe static_cast<T*>(void*):
#include <stdio.h>
struct Callback
{
void(*fun)(void* arg);
void* arg;
};
void invoke(Callback c)
{
c.fun(c.arg);
}
// a member-function to Callback function adapter
template<class T, void(T::*mem_fun)()>
Callback makeCallback(T* obj)
{
struct local
{
static void call(void* p)
{
(static_cast<T*>(p)->*mem_fun)();
}
};
Callback c = { local::call, obj };
return c;
}
struct X
{
void foo() { printf("foo\n"); }
void bar() { printf("bar\n"); }
// bar to callback adapter
static void bar_cb(void* p) { static_cast<X*>(p)->bar(); }
};
int main()
{
X x;
// autogenerate member function adapter
invoke(makeCallback<X, &X::foo>(&x));
// or use an existing adapter
Callback c = { X::bar_cb, &x };
invoke(c);
}
--
Max
Generated by PreciseInfo ™
"No better title than The World significance of the
Russian Revolution could have been chosen, for no event in any
age will finally have more significance for our world than this
one. We are still too near to see clearly this Revolution, this
portentous event, which was certainly one of the most intimate
and therefore least obvious, aims of the worldconflagration,
hidden as it was at first by the fire and smoke of national
enthusiasms and patriotic antagonisms.
You rightly recognize that there is an ideology behind it
and you clearly diagnose it as an ancient ideology. There is
nothing new under the sun, it is even nothing new that this sun
rises in the East...
these experienced officers of all latterday revolutions, the
Jews?
There is scarcely an even in modern Europe that cannot be
traced back to the Jews... all latterday ideas and movements
have originally spring from a Jewish source, for the simple
reason, that the Jewish."
(The Secret Powers Behind Revolution, by Vicomte Leon de Poncins,
p. 226)