Function pointer help

G

ghulands

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);

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?

Any help is greatly appreciated.

Thanks,
Greg
 
G

ghulands

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);

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?

Any help is greatly appreciated.

Thanks,
Greg

Found the solution: static_cast<>

plane->addEventListener(gun,
static_cast<CFEventHandler>(&MachineGun::handleEvent), 0);
 
J

James Kanze

Just curious, but: what is the type of gun, and why did you cast
it?
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. Typically,
it's not quite as dangerous as it looks, because almost always,
you're registering a member function of the class you're in; the
first argument is almost always "this".

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

Maxim Yegorushkin

Just curious, but: what is the type of gun, and why did you cast
it?


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);
}
 
J

James Kanze

[...]
wxWidgets is one example.

I said that there was more than one. That wasn't the one where
I'd seen it:).
They argue that if there are hundreds of events there should
be hundreds of virtual functions.

Or hundreds of different abstract bases.
Which leads to relatively
large virtual tables for every derived class.

Woopey do.

In practice, it's probably a good idea to regroup different
types of events, e.g. mouse events, keyboard events, focus
events, etc. Or maybe not... finding the ideal grouping isn't
obvious. Anyway, it's a minor problem at worst; the proposed
alternative is certainly an order of magnitude worst.

[...]
IMHO, using member function pointers for callbacks is always a
design mistake because it requires casting member function
pointers, which is not portable.

There's no problem with portabilty, as long as the user doesn't
make any mistakes. There's a serious problem with robustness,
however, since you really have no way of catching those
mistakes.
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*):

The code you propose is no safer than the pointer to member
solution with my template wrapper. And a lot uglier and more
difficult to understand.
 
M

Maxim Yegorushkin

[]
There's no problem with portabilty, as long as the user doesn't
make any mistakes.  There's a serious problem with robustness,
however, since you really have no way of catching those
mistakes.

Although it works on practice, is it not undefined behaviour to cast a
derived class member function pointer back to base class member
function pointer?
The code you propose is no safer than the pointer to member
solution with my template wrapper.

I think it is, because it does not rely on casting member function
pointers.
And a lot uglier and more difficult to understand.

It looks alien to you probably because you are not used to it.

I agree that having to adapt a member function to a regular (static)
function may seem onerous at first. However, I see no fundamental
difference (in the context of callbacks) between:

struct X
{
void foo();
};

and:

struct X
{
static void foo(X* that);
};

Speaking purely technically, I think C-style callbacks are superior to
member function pointer based callbacks:

1) they can be bound both to plain functions and to member functions.
2) the callback structure occupies less memory, since a regular
function pointer is 2-3 times smaller than a member function pointer.
3) they do not rely on any undefined behaviour.
 
J

James Kanze

[]
IMHO, using member function pointers for callbacks is
always a design mistake because it requires casting member
function pointers, which is not portable.
There's no problem with portabilty, as long as the user
doesn't make any mistakes.  There's a serious problem with
robustness, however, since you really have no way of
catching those mistakes.
Although it works on practice, is it not undefined behaviour
to cast a derived class member function pointer back to base
class member function pointer?

No. Undefined practice only creeps in if you use it with a
pointer that doesn't actually point to a derived class of the
correct type. (I had the same reaction the first time I saw
it:). It doesn't like like it should work, especially if e.g.
virtual inheritance et al. are involved. But the standard says
it has to.)
I think it is, because it does not rely on casting member
function pointers.

It requires using a void*, which in my experience can be even
more dangerous.
It looks alien to you probably because you are not used to it.

Certainly:). (Actually, I can follow it, because when
interfacing to C, you often have to do things like that. It is
the first time I've seen it used when there was no C involved,
however.)

I think what I really don't like about it is that it doesn't
look wierd enough, given what you're actually doing.

[...]
Speaking purely technically, I think C-style callbacks are
superior to member function pointer based callbacks:

Quite frankly, neither come close to using virtual functions.
However...
1) they can be bound both to plain functions and to member functions.

If that is a requirement, of course (e.g. to be able to
interface with C as well), then your solution is the way to go.
2) the callback structure occupies less memory, since a
regular function pointer is 2-3 times smaller than a member
function pointer.

As if that's seriously going to make any difference. This is a
GUI we're talking about. With large, graphic images behind the
scenes; a couple of Meg, at the least. And even with a hundred
callbacks, you won't be adding over a KB.
3) they do not rely on any undefined behaviour.

Nor does the pointer to member solution.
 
M

Maxim Yegorushkin

Although it works on practice, is it not undefined behaviour
to cast a derived class member function pointer back to base
class member function pointer?

No.  Undefined practice only creeps in if you use it with a
pointer that doesn't actually point to a derived class of the
correct type.  (I had the same reaction the first time I saw
it:).  It doesn't like like it should work, especially if e.g.
virtual inheritance et al. are involved.  But the standard says
it has to.)
[]
3) they do not rely on any undefined behaviour.

Nor does the pointer to member solution.

Sorry, I was wrong with regards to UB arising when casting derived
class member function pointer to base class one. It seems that
static_cast<> is enough to do the trick.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,169
Messages
2,570,917
Members
47,458
Latest member
Chris#

Latest Threads

Top