Wywołanie metody klasy jako funkcji callback

0

Cześć,

Wieki nie miałem już nic wspólnego z C++, stąd moje pytanie. Dzieci znajomej mają problem, muszą wywołać funkcję z dll-ki której trzeba podać jako parametr funkcję callback.
I wszystko byłoby ok gdyby nie to, że chcą przekazać metodę klasy. Wydaje mi się, że w "normalny" sposób jest to nie do zrobienia. Ale jak wspomniałem, wieki nie pisałem nic w C++, po prostu nie pamiętam.

Poniżej krótki fragment kodu który myślę, że może pokazać problem. Zakomentowane jest przypisanie metody do wskaźnika funkcji ;)
Z góry dzięki za info.


#include "stdafx.h"
#include <conio.h>

typedef int(*nazwaTypuT)(int, int);

int funkcjaX(int a, int b)
{
    return(a + b);
}

class Klasa
{
public:
    nazwaTypuT pWskaznikNaFunkcje;

    int metoda(int a, int b)
    {
        return(a+b);
    }

    int metoda2(int a, int b)
    {
        //pWskaznikNaFunkcje = metoda; // to nie ma prawa zadziałać bo to metoda,
        pWskaznikNaFunkcje = funkcjaX; //a to zadziała
        return ( pWskaznikNaFunkcje(5, 7) );
    }
};

int main()
{
    Klasa* instancjaKlasy = new Klasa;
    printf( "%i\n", instancjaKlasy->metoda(1, 2) );
    printf("%i\n", instancjaKlasy->metoda2(1, 2));
    getch();
    return 0;
}
0

W tym prostym przykładzie metodę o nazwie metoda można zrobić statyczną
static int metoda(int a, int b) { return(a+b); }
Wtedy jej adres można przypisać do pWskaznikNaFunkcje tak:
pWskaznikNaFunkcje = &Klasa::metoda;

Jeśli miałaby być niestatyczna to typ wskaźnika można zadeklarować tak:
typedef int(Klasa::*nazwaTypuT)(int, int);
Natomiast trzeba pamiętać, że metodę niestatyczną wykonuje się na obiekcie:
(this->*pWskaznikNaFunkcje)(5, 7)

Nie wiem tylko czy konwersja int(Klasa::*nazwaTypuT)(int, int) na int(*nazwaTypuT)(int, int) jest możliwa i czy ma w ogóle jakiś sens.

2

Czy callback ma parametr nazwany context albo coś takiego?

Na przykład:

void do_foo(int param1, int param2, void (*callback)(void*, int), void* context);

Wtedy jako context możesz podać this i callback może go zcastować:

struct foo_doer
{
    void execute() {
        do_foo(42, 42, +[](void* ptr, int result) {
            static_cast<foo_doer*>(ptr)->on_done(result);
        }, this);
    }

    void on_done(int result) {
        // bla bla bla
    }
};

Jeśli tego nie ma to musisz w jakiejś globalnej zmiennej przetrzymać adres obiektu, ale to rozwiązanie bardzo nieprzyjemne.

0

Wielkie dzięki. O to chodziło.

0

Można jeszcze użyć std::function i std::bind

#include <functional>

typedef std::function< int( int, int ) > FuncType;

int global_func( int a, int b )
{
  return a+b;
}

class Foo
{
  public:
    FuncType func;
    int class_func( int a, int b )
    {
      return a+b;
    }
    int call_func( int a, int b )
    {
      return func( a, b );
    }
};

int main( int argc, char** argv )
{
  Foo foo;
  foo.func = &global_func;
  foo.call_func( 1, 2 );
  foo.func = std::bind( &Foo::class_func, &foo, std::placeholders::_1, std::placeholders::_2 );
  foo.call_func( 2, 3 );
  return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0