473,230 Members | 1,555 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,230 software developers and data experts.

Function pointer help

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

Oct 23 '08 #1
7 3766
On Oct 23, 4:15*pm, "ghula...@gmail.com" <ghula...@gmail.comwrote:
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::handleEve nt), 0);

Oct 24 '08 #2
gh******@gmail.com wrote:
On Oct 23, 4:15 pm, "ghula...@gmail.com" <ghula...@gmail.comwrote:
>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::handleEve nt), 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
Oct 24 '08 #3
On Oct 24, 3:39 am, Victor Bazarov <v.Abaza...@comAcast.netwrote:
ghula...@gmail.com wrote:
On Oct 23, 4:15 pm, "ghula...@gmail.com" <ghula...@gmail.comwrote:
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::handleEve nt), 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:ja*********@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
Oct 24 '08 #4
On Oct 24, 8:51*am, James Kanze <james.ka...@gmail.comwrote:
On Oct 24, 3:39 am, Victor Bazarov <v.Abaza...@comAcast.netwrote:
ghula...@gmail.com wrote:
On Oct 23, 4:15 pm, "ghula...@gmail.com" <ghula...@gmail.comwrote:
>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::handleEve nt), 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
Oct 24 '08 #5
On Oct 24, 2:50*pm, James Kanze <james.ka...@gmail.comwrote:

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

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

58
by: jr | last post by:
Sorry for this very dumb question, but I've clearly got a long way to go! Can someone please help me pass an array into a function. Here's a starting point. void TheMainFunc() { // Body of...
5
by: amit kumar | last post by:
I am calling a function which returns pointer to a map. The declaration of the map is map<int,vectxyz*>. vectxyz is a vector containing pointer to a class xyz. For map<int,vectxyz*>* p1 In the...
11
by: JKop | last post by:
Take the following simple function: unsigned long Plus5Percent(unsigned long input) { return ( input + input / 20 ); } Do yous ever consider the possibly more efficent:
3
by: Jan-Henrik Grobe | last post by:
Hallo, I am coming to this newsgroup with a very strange Problem. I have two c++ files A.cpp and B.cpp....In A.cpp I am creating an openGL window and in B.cpp I have stored the callback...
2
by: sushil | last post by:
+1 #include<stdio.h> +2 #include <stdlib.h> +3 typedef struct +4 { +5 unsigned int PID; +6 unsigned int CID; +7 } T_ID; +8 +9 typedef unsigned int (*T_HANDLER)(void); +10
7
by: Mike D. | last post by:
I have a problem with a dynamic library I am developing, but it is really more of a pointer issue than anything else. Hopefully someone here can lend me some assistance or insight into resolving...
4
by: anonymous | last post by:
Thanks your reply. The article I read is from www.hakin9.org/en/attachments/stackoverflow_en.pdf. And you're right. I don't know it very clearly. And that's why I want to understand it; for it's...
17
by: Razzel | last post by:
I created this as a test: #include <time.h> main(){ printf(X1: %s\n", putim()); printf(X2: %s\n", putim()); } putim() { time_t t; time(&t); return(ctime(&t));
9
by: Morten Lemvigh | last post by:
Is it possible to pass a pointer to a constructor or a class definition as argument to a function? Maybe in a way similar to passing function pointers...? The function should construct a number...
20
by: MikeC | last post by:
Folks, I've been playing with C programs for 25 years (not professionally - self-taught), and although I've used function pointers before, I've never got my head around them enough to be able to...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
0
by: jianzs | last post by:
Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
Git
by: egorbl4 | last post by:
Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ...
1
by: davi5007 | last post by:
Hi, Basically, I am trying to automate a field named TraceabilityNo into a web page from an access form. I've got the serial held in the variable strSearchString. How can I get this into the...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.