[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.c++

Problems with callback

maverik

11/26/2008 6:36:00 PM

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

Puppet_Sock

11/26/2008 7:01:00 PM

0

On Nov 26, 1:36 pm, maverik <maverik.m...@gmail.com> wrote:
[snip]
> 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

Andrey Tarasevich

11/26/2008 7:33:00 PM

0

maverik wrote:
>
> Question: is there a way in that i can do this (can register class
> method as a callback):
>
> m_listView.SetMouseButtonUpCb(&MyClass::DoClick);
>

http://www.parashift.com/c++-faq-lite/pointers-to-members.htm...

--
Best regards,
Andrey Tarasevich

Juha Nieminen

11/27/2008 10:50:00 PM

0

maverik wrote:
> 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.

blargg.h4g

11/28/2008 6:01:00 PM

0

Juha Nieminen wrote:
[...]
> 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.

That sounds very wrong:

void callback( void* obj )
{
reinterpret_cast<Foo>(obj).member_func();
}

even if you meant "reinterpret-casts the void* to A POINTER TO the type of
the class", it's still bad advice because reinterpret_cast yields
implementation-defined results:

void callback( void* obj )
{
reinterpret_cast<Foo*>(obj)->member_func();
}

Using static_cast is the way to go, since it mirrors the conversion made
earlier:

// earlier:
void set_callback( void (*func)( void* obj ), void* obj );
Foo foo;
set_callback( callback, &foo );

void callback( void* obj )
{
static_cast<Foo*>(obj)->member_func();
}

James Kanze

11/28/2008 7:35:00 PM

0

On Nov 27, 11:49 pm, Juha Nieminen <nos...@thanks.invalid> wrote:
> maverik wrote:
> > 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.

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< Base* >( &theObject ) ) ;

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

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