如何传递函数指针(回调)并在不知道其类型的情况下调用它?

时间:2019-10-21 16:07:51

标签: c++ c++11 callback

我有一个函数指针作为纯虚拟基类的成员。我想将此指针传递给一个不了解这些类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 个答案:

答案 0 :(得分:3)

#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,那么您将不得不玩很多不同的游戏。

答案 1 :(得分:2)

要在不知道要调用的函数的确切类型时获取函数指针,请使用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()
}