Problems with callback

Discussion in 'C++' started by maverik, Nov 26, 2008.

  1. maverik

    maverik Guest

    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.
    maverik, Nov 26, 2008
    #1
    1. Advertising

  2. maverik

    Puppet_Sock Guest

    On Nov 26, 1:36 pm, maverik <> 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
    Puppet_Sock, Nov 26, 2008
    #2
    1. Advertising

  3. Andrey Tarasevich, Nov 26, 2008
    #3
  4. 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.
    Juha Nieminen, Nov 27, 2008
    #4
  5. maverik

    James Kanze Guest

    On Nov 27, 11:49 pm, Juha Nieminen <> 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:
    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
    James Kanze, Nov 28, 2008
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Brian Vallelunga

    Cache with Callback problems... threading?

    Brian Vallelunga, Jul 23, 2003, in forum: ASP .Net
    Replies:
    3
    Views:
    367
    Natty Gur
    Jul 27, 2003
  2. Jim Hammond
    Replies:
    2
    Views:
    1,213
    Jim Hammond
    Oct 24, 2003
  3. Borr
    Replies:
    2
    Views:
    1,638
    bruce barker
    Nov 5, 2003
  4. Joe Fallon

    ASP.Net Cache Callback Problem

    Joe Fallon, Jan 20, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    4,877
    Joe Fallon
    Jan 20, 2004
  5. Glen
    Replies:
    3
    Views:
    563
    Craig Burkett
    Jan 23, 2004
Loading...

Share This Page