Problems with callback

M

maverik

Hi.

I have class ListView

ListView.h:

class ListView {
...
typedef void (*ListViewCallback)(ListViewItem& );
...
void SetMouseButtonUpCb(ListViewCallback );
...
};

and some other class MyClass:

MyClass.h:

#include "ListView.h"
class MyClass {
...
ListView m_listView;
...
};

MyClass.cpp:

#include "ListView.h"

void
MyClass::Foo() {
m_listView.SetMouseButtonUpCb(&GDoClick); // That's ok
m_listView.SetMouseButtonUpCb(&MyClass::DoClick); // Error

// 'ListView::SetMouseButtonUpCb' : cannot convert parameter 1 from
'void (__thiscall MyClass::*) (ListViewItem &)' to
'ListView::ListViewCallback'

}

void
MyClass::DoClick(ListViewItem& item) {
...
}

void
GDoClick(ListViewItem& item) {
...
}

Where DoClick(ListViewItem& ) is member of MyClass and GDoClick
(ListViewItem& ) is a global function.
As you can see registring global function GDoClick as a callback is
OK, but registring a member of the class produce an error.
Unfortunately, I have some restrictions:

1. I cannot change callback definition. For example, I can't write

typedef void (*MyCLass::ListViewCallback)(ListViewItem& );

2. I cannot use global function as a callback. Can't do this:

m_listView.SetMouseButtonUpCb(&GDoClick);

Question: is there a way in that i can do this (can register class
method as a callback):

m_listView.SetMouseButtonUpCb(&MyClass::DoClick);

Thanks.
 
P

Puppet_Sock

Question: is there a way in that i can do this (can register class
method as a callback):

    m_listView.SetMouseButtonUpCb(&MyClass::DoClick);

This is an evergreen question in C++.

Think carefully what you are doing. A non-static
member function has not got an object to work in
until that object is created. And it can't find
that object unless you tell it how some way,
such as by using the object's name, or by calling
it through the object's address.

So your example

m_listView.SetMouseButtonUpCb(&MyClass::DoClick);

can't work without some modifications. Which
specific instance of MyClass do you want to
do the DoClick op?

If you are restricted in being unable to change the
signature of the callback then you have to use some
kind of "look up" strategy.

Someplace, you have to store the address of the
specific object you want. Then, you make a static
callback function that uses that address to forward
the request to the specific object, and returning
the appropriate data where it belongs.

In some callback systems you can pass the address
in as a parameter. In other cases you need some
way to save the object's address in your code,
and some way to pick the specific object you want.

If I recall, Microsoft windows lets you pass an
extra parameter to such callbacks. This might
not be acceptable as an address, but might be
ok as something that lets you look up an object
instance in a table, and get the address. The
system uses window handles or something.
Window handle or something, if I recall.
Socks
 
J

Juha Nieminen

maverik said:
Question: is there a way in that i can do this (can register class
method as a callback):

m_listView.SetMouseButtonUpCb(&MyClass::DoClick);

A member function can not be called using a function pointer only for
the simple reason that a member function *always* needs an object as
well. (Basically you can think that a pointer to the object is always
passed to the member function as the first parameter. Which is usually
actually the case internally with most compilers.)

If the callback mechanism only supports taking a function pointer and
nothing else, then it obviously cannot call a member function because it
has no object pointer to give.

Most callback function mechanisms support taking some user data,
usually in the form of a void*. What you do is that you give a pointer
to the object as this void*, and then use a regular callback function
which receives that void*. That callback function then just
reinterpret-casts the void* to the type of the class and uses it to call
the member function.

If you are writing the callback mechanism yourself, then you can
automatize this to great lengths using templates, but it's a bit
complicated.
 
J

James Kanze

A member function can not be called using a function pointer
only for the simple reason that a member function *always*
needs an object as well. (Basically you can think that a
pointer to the object is always passed to the member function
as the first parameter. Which is usually actually the case
internally with most compilers.)
If the callback mechanism only supports taking a function
pointer and nothing else, then it obviously cannot call a
member function because it has no object pointer to give.

Back in the good old days, people used static variables (and
"good" is meant very, very ironically).
Most callback function mechanisms support taking some user
data, usually in the form of a void*. What you do is that you
give a pointer to the object as this void*, and then use a
regular callback function which receives that void*. That
callback function then just reinterpret-casts the void* to the
type of the class and uses it to call the member function.

First, it's static_cast you want, not reinterpret_cast. And
second, you have to be very, very careful; the static_cast must
be to exactly the type which served to get the void*. So, for
example, something like:

extern "C" void callback( void* p )
{
static_cast< Base* >( p )->doSomething() ;
}

// ...

Derived theObject ;
registerCallback( &callback, &theObject ) ;

is undefined behavior (supposing registerCallback takes a void*
as second argument). You must do:

registerCallback( &callback,
static_cast said:
If you are writing the callback mechanism yourself, then you
can automatize this to great lengths using templates, but it's
a bit complicated.

Particularly if the interface requires an ``extern "C"''
function (which is usually the case).
 

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
473,995
Messages
2,570,231
Members
46,820
Latest member
GilbertoA5

Latest Threads

Top