Как передать указатель на функцию (обратный вызов) и вызвать его, не зная его типа? - PullRequest
1 голос
/ 21 октября 2019

У меня есть указатель на функцию в качестве члена чисто виртуального базового класса. Я хотел бы передать этот указатель в библиотеку, которая не знает ни об одном из этих классов, MyBase или MyClass, а затем вызвать указатель функции в качестве обратного вызова в MyClass. Я тоже пишу библиотеку. Я хочу, чтобы разделяемая библиотека вызывала обратный вызов в MyClass.

Мой вопрос: как передать указатель на функцию в качестве аргумента функции и вызвать ее, не зная ничего о самом классе.

Я рассматривал указатель на указатель на функцию, но не знал, как правильно приводить.

class MyBase {
    public:
        virtual void callback() = 0;
        void (MyBase::*callback_ptr)();
};

class MyClass : public MyBase {
    public:
        MyClass();
        void callback() { cout << "callback called" << endl; };
};

main.cpp

{
    MyClass my_class;
    my_class->callback_ptr = &MyBase::callback;

    lib->set_callback(my_class->callback_ptr);
}

lib.cpp

class MyLib {
    public:
        // how to declare the member function pointer here?
        void** callback_ptr;

        // how to write sig here?
        set_callback(ptr) { callback_ptr = ptr }

        running() {  
            // how to call the callback here w/o knowing it's type?
        }
}

Ответы [ 2 ]

3 голосов
/ 21 октября 2019
#include <iostream>
#include <functional>

using namespace std;

class Foo {
public:
    void myFunction() {
        cout << "Foo::myFunction()\n";
    }
};

void myAPICall(std::function<void()> arg) {
    arg();
}

int main(int, char**) {
    Foo foo;

    // Using a lambda
    myAPICall( [&]() { foo.myFunction(); } );

    // Using bind
    myAPICall( std::bind(&Foo::myFunction, foo) );

    return 0;
}

Выход:

$ g++ -std=c++11 f.cpp -o f && f
Foo::myFunction()
Foo::myFunction()

Предполагается, что вы управляете вызываемым API, и он использует std :: function, как и мой код. Если он принимает указатель на функцию в стиле C, а не std :: function, то вам придется играть в самые разные игры.

2 голосов
/ 21 октября 2019

Чтобы получить указатель на функцию, когда вы не знаете точный тип вызываемой функции, используйте std::function из заголовка <functional>.

class MyLib {
    public:
        // how to declare the member function pointer here?
        std::function<void()> callback_ptr;

        // how to write sig here?
        void set_callback(std::function<void()> ptr) { callback_ptr = ptr; }

        void running() {  
            callback_ptr();
        }
};

Чтобы использовать функцию-член какstd::function, используйте std::bind:

int main()
{
    MyClass my_class;
    MyLib my_lib;

    my_lib.set_callback(std::bind(&MyClass::callback, &my_class));
    my_lib.running(); // calls my_class.callback()
}
...