Callback Trouble

N

Nashirak

I am trying to implement callbacks in C++. I am modeling my callbacks
after some of the stuff that was done in wxWidgets (if anyone is
familiar with that). The syntax is as follows:

// Header
DEFINE_NAMESPACE_BEGIN(NGMX)

typedef void (PI_PluginAPI::*KMKeyboardMethod)(const KeyboardEvent
*event);

class KM_Keymap : public PI_PluginAPI
{
public:

KM_Keymap();

// More functions follow ....

bool AddKeymapEntryMethod(const char *top_entry, const char
*name,const char *desc, PI_PluginAPI *obj, KMKeyboardMethod func, void
*userdata=NULL);

private:

// Private stuff here
};
DEFINE_NAMESPACE_END

Then I have a calling class. It structure is as follows:

// Header
class My_Plugin : virtual public NGMX::pI_PluginAPI
{
public:
My_Plugin();

// More stuff ...

void ShowStuffCB(const NGMX::KeyboardEvent *event);

private:
// Private stuff
};

To connect the callback I make this call in a method inside of the
My_Plugin (My_Plugin class uses the NGMX namespace up top) class:

// In source
m_keymap->AddKeymapEntryMethod("BASE","Show Stuff","Turn on and off
Stuff",this,(KMKeyboardMethod)&My_Plugin::ShowStuffCB);

Now the error I am getting is as follows (in Visual Studio 2003):
error C2664: 'NGMX::KM_Keymap::AddKeymapEntryMethod' : cannot convert
parameter 5 from 'void (__thiscall My_Plugin::* )(void)' to
'NGMX::KMKeyboardMethod'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast

So it appears that it doesn't like the &My_Plugin::ShowStuffCB
parameter. My_Plugin inherits from PI_PluginAPI so I don't know why
the cast doesn't work. I am not sure what I am doing wrong. Anyone see
something glaring that needs to be fixed? Thanks in advance for you
help.
 
A

Alf P. Steinbach

* Nashirak:
I am trying to implement callbacks in C++. I am modeling my callbacks
after some of the stuff that was done in wxWidgets (if anyone is
familiar with that). The syntax is as follows:

// Header
DEFINE_NAMESPACE_BEGIN(NGMX)

Please don't hide namespace declarations etc. in macros.


typedef void (PI_PluginAPI::*KMKeyboardMethod)(const KeyboardEvent
*event);

The less you use raw pointers, the better.

Pointers to member functions are especially bad (in general).

Try something like

struct KeyboardEventHandler
{
virtual void onEvent( KeyboardEvent const& ) = 0;
};


class KM_Keymap : public PI_PluginAPI

Why use prefixes instead of namespaces?

{
public:

KM_Keymap();

// More functions follow ....

bool AddKeymapEntryMethod(const char *top_entry, const char
*name,const char *desc, PI_PluginAPI *obj, KMKeyboardMethod func, void
*userdata=NULL);

As mentioned raw pointers are bad, member function pointers especially
bad, and void* pointers, used above, are simply unacceptable in high
level code (if you must interface to C then that's another matter, but
the above doesn't).


private:

// Private stuff here
};
DEFINE_NAMESPACE_END

Then I have a calling class. It structure is as follows:

// Header
class My_Plugin : virtual public NGMX::pI_PluginAPI
{
public:
My_Plugin();

// More stuff ...

void ShowStuffCB(const NGMX::KeyboardEvent *event);

private:
// Private stuff
};

To connect the callback I make this call in a method inside of the
My_Plugin (My_Plugin class uses the NGMX namespace up top) class:

// In source
m_keymap->AddKeymapEntryMethod("BASE","Show Stuff","Turn on and off
Stuff",this,(KMKeyboardMethod)&My_Plugin::ShowStuffCB);

C style casts are bad.



Now the error I am getting is as follows (in Visual Studio 2003):
error C2664: 'NGMX::KM_Keymap::AddKeymapEntryMethod' : cannot convert
parameter 5 from 'void (__thiscall My_Plugin::* )(void)' to
'NGMX::KMKeyboardMethod'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast

The error message is not related to any code shown.

Reproduce the error in a smallest possible complete program and post the
code if that effort in itself doesn't help you.

See the FAQ for help about how to post a question about code that
doesn't work as expected.

So it appears that it doesn't like the &My_Plugin::ShowStuffCB
parameter. My_Plugin inherits from PI_PluginAPI so I don't know why
the cast doesn't work. I am not sure what I am doing wrong. Anyone see
something glaring that needs to be fixed? Thanks in advance for you
help.

See above.


Cheers, & hth.,

- Alf
 
R

Roland Pibinger

I am trying to implement callbacks in C++. I am modeling my callbacks
after some of the stuff that was done in wxWidgets (if anyone is
familiar with that). The syntax is as follows: [...]
Now the error I am getting is as follows (in Visual Studio 2003):
error C2664: 'NGMX::KM_Keymap::AddKeymapEntryMethod' : cannot convert
parameter 5 from 'void (__thiscall My_Plugin::* )(void)' to
'NGMX::KMKeyboardMethod'
Types pointed to are unrelated; conversion requires reinterpret_cast,
C-style cast or function-style cast

AFAICS, the problem is that member function pointers are not
polymorphic in C++. The following is a Reader's Digest version of your
code with some additions:

class KeyboardEvent;

class PI_PluginAPI {

};

typedef
void (PI_PluginAPI::*KMKeyboardMethod)(const KeyboardEvent *event);

class KM_Keymap : public PI_PluginAPI {
public:
bool AddKeymapEntryMethod(PI_PluginAPI *obj, KMKeyboardMethod func);
};


class My_Plugin : virtual public PI_PluginAPI
{
public:
void ShowStuffCB(const KeyboardEvent *event);

void foo() {
// works: calling member function via member function pointer
((*this).*(&My_Plugin::ShowStuffCB))(0);

// doesn't work: what you try to do would be similar to
// the following
PI_PluginAPI* pApi = this;
((*pApi).*(&My_Plugin::ShowStuffCB))(0);

// see error message: a pointer to a (non-static) derived class
// member function is not an pointer to a base memebr class
// function
m_keymap.AddKeymapEntryMethod(this, &My_Plugin::ShowStuffCB);
}

private:
KM_Keymap m_keymap;
};

BTW, a good callback library can be found here:
http://www.codeproject.com/cpp/FastDelegate.asp
 
N

Nashirak

AFAICS, the problem is that member function pointers are not
polymorphic in C++. The following is a Reader's Digest version of your
code with some additions:

Thanks for your responses. I played around with this a little more
this weekend and found that once I made My_Plugin inherit from
PI_PluginAPI in a non-virtual manner, everthing seemed to work and
compile. So by changing:

class My_Plugin : virtual public PI_PluginAPI

to

class My_Plugin : public PI_PluginAPI

Everything seemed to work ok.
Thanks again for your responses. I will take a look at that callback
library.
 
A

Alf P. Steinbach

* Nashirak:
Thanks for your responses. I played around with this a little more
this weekend and found that once I made My_Plugin inherit from
PI_PluginAPI in a non-virtual manner, everthing seemed to work and
compile. So by changing:

class My_Plugin : virtual public PI_PluginAPI

to

class My_Plugin : public PI_PluginAPI

Everything seemed to work ok.

It shouldn't. Your error message said you supplied a member function
with signature void (My_Plugin::*)() as actual argument to void
(PI_PluginAPI::*)(const KeyboardEvent*). Do you spot the difference?

Thanks again for your responses. I will take a look at that callback
library.

Take a look at your code first.

Cheers, & hth.,

- Alf
 
J

James Kanze

Nashirak said:
I am trying to implement callbacks in C++. I am modeling my
callbacks after some of the stuff that was done in wxWidgets
(if anyone is familiar with that). The syntax is as follows:
// Header
DEFINE_NAMESPACE_BEGIN(NGMX)

Do you really still have to deal with compilers which don't
support namespaces?
typedef void (PI_PluginAPI::*KMKeyboardMethod)(const KeyboardEvent
*event);
class KM_Keymap : public PI_PluginAPI
{
public:

// More functions follow ....
bool AddKeymapEntryMethod(const char *top_entry, const char
*name,const char *desc, PI_PluginAPI *obj, KMKeyboardMethod func, void
*userdata=NULL);

// Private stuff here
};
DEFINE_NAMESPACE_END
Then I have a calling class. It structure is as follows:
// Header
class My_Plugin : virtual public NGMX::pI_PluginAPI
{
public:
My_Plugin();
// More stuff ...
void ShowStuffCB(const NGMX::KeyboardEvent *event);
private:
// Private stuff
};
To connect the callback I make this call in a method inside of the
My_Plugin (My_Plugin class uses the NGMX namespace up top) class:
// In source
m_keymap->AddKeymapEntryMethod("BASE","Show Stuff","Turn on and off
Stuff",this,(KMKeyboardMethod)&My_Plugin::ShowStuffCB);

As has been pointed out, this type conversion isn't allowed if
the base is virtual.

More generally, although well established "existing practice",
it's a bad existing practice, and is not the way I would
implement callbacks. Since you have to inherit from a specific
base class anyway, just define a pure virtual function in it,
and use that for the callback. Something like:

class PluginAPI
{
public:
virtual ~PluginAPI() {}
// You might want to use a reference parameter here,
// since I'd be very surprised that you want to support
// calling this function with a null pointer.
virtual void notifyKeyboardEvent(
KeyboardEvent const* event ) = 0 ;
// ...
} ;

Given this, you can add a class template which derives from it,
and forwards to an arbitrary function in an arbitrary class, but
it's generally not worth the bother.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,070
Latest member
BiogenixGummies

Latest Threads

Top