[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

Function pointer help

ghulands@gmail.com

10/23/2008 11:16:00 PM

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

9 Answers

ghulands@gmail.com

10/24/2008 12:08:00 AM

0

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



Victor Bazarov

10/24/2008 1:39:00 AM

0

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

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

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

James Kanze

10/24/2008 7:52:00 AM

0

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

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Maxim Yegorushkin

10/24/2008 9:20:00 AM

0

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


James Kanze

10/24/2008 1:51:00 PM

0

On Oct 24, 11:19 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> 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:

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

I said that there was more than one. That wasn't the one where
I'd seen it:-).

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

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.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Maxim Yegorushkin

10/24/2008 4:58:00 PM

0

On Oct 24, 2:50 pm, James Kanze <james.ka...@gmail.com> wrote:

[]

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

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

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.

--
Max

James Kanze

10/24/2008 8:33:00 PM

0

On Oct 24, 6:57 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:
> On Oct 24, 2:50 pm, James Kanze <james.ka...@gmail.com> wrote:

> []

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

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

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

> > And a lot uglier and more difficult to understand.

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

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Maxim Yegorushkin

10/27/2008 8:24:00 AM

0

On Oct 24, 8:32 pm, James Kanze <james.ka...@gmail.com> wrote:
> On Oct 24, 6:57 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
> wrote:
>
> > On Oct 24, 2:50 pm, James Kanze <james.ka...@gmail.com> wrote:
> > []
> > > > 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.)

[]

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

--
Max

iL_WeReo

11/11/2011 4:43:00 AM

0

On Nov 10, 8:01 pm, "sweetbac" <sweet...@sbcglobal.net> wrote:
> "iL_Schizo" <caljamsc...@yahoo.com> wrote in message
> > I mean ass-fucking a 10 year old in a wet shower situation.
> > C'mon. I hope he has a small dick.
>
> Is that why you're soo damn obsessed with children, Scott?

I'm obsessed on the date you're going to grow up. Take 11-11-11.