C++成员函数指针转C-Style普通函数指针

 最近遇到一个需求,需要将C++类成员函数强制转化为C-Style的回调函数,以供C原生API调用。

C++实现注册回调函数机制可分为2类:

  1. 完全使用C++风格(参照如下代码class A1);
  2. 使用C++代码包装C原生API(参照如下代码class A2);

理想状态下,我们更倾向于采用1的方式进行开发。推荐使用C++11新特性lambda定义回调函数,使用std::function接收和保存不同class的成员函数指针。

如果想借用优质的C原生API注册回调,则需要考虑将成员函数指针强制转化为严格的C-Style普通函数指针。推荐使用C++17新特性inline static构造如下Wrapper类——CallbackWrapper。

当然,如果我们对回调函数访问类成员变量和成员函数没有强需要,也可以在类内声明友元函数或者static静态成员函数来注册回调函数。此方法不做赘述。

#include <iostream>
#include <functional>
#include <unordered_map>
#include <string>

// ============================================================================
typedef void(*func_callback)(const char*xx, void* yy);
static std::unordered_map<const char*, func_callback> g_funcs;
static std::unordered_map<const char*, void*> g_yys;

static void g_regist_handler(const char*xx, void(*func)(const char*xx, void *yy), void *yy) {
    g_funcs[xx] = func;
    g_yys[xx] = yy;
    std::cout << "zhong yu deng dao ni!" <<  std::endl;
}

static void g_send(const char* x) {
    g_funcs[x](x, g_yys[x]);
}

// ============================================================================
class A1 {
public:
    using lambda_callback = std::function<void(const char*xx, void *yy)>;
    typedef void(*func_callback)(const char* xx, void* yy);
    A1() = default;
    ~A1() = default;
    void regist_handler(const char* x, lambda_callback func, void* y) {
        _handlers[x] = func;
        _params[x] = y;
    }
    void send(const char* x) {
        _handlers[x](x, _params[x]);
    }
private:
    std::unordered_map<std::string, lambda_callback> _handlers;
    std::unordered_map<std::string, void*> _params;
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class A2 {
public:
    typedef void(*func_callback)(const char*xx, void *yy);
    A2() = default;
    ~A2() = default;
    void regist_handler(const char* x, func_callback func, void* y) {
        g_regist_handler(x, func, y);
    }
private:
};
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

class CallbackWrapper {
public:
    static void wrapper_func(const char*xx, void *yy) {
        broker_func(xx, yy);
    }
    // g++ -std=c++17
    inline static std::function<void(const char*xx, void *yy)> broker_func;
};

class B {
public:
    B() = default;
    ~B() = default;
    void print() {
        std::cout << "B obj." << std::endl;
    }
    void on_test_handler(const char*xx, void *yy) {
        this->print();
        std::cout << xx << "," << (const char*)yy << std::endl;
    }
    void init() {
        // ABC
        _a1.regist_handler(
            "ABC",
            [this](const char*xx, void *yy){
                this->on_test_handler(xx, yy);
            },
            (void*)"111123"
        );
        // DEF
        _a1.regist_handler(
            "DEF",
            [this](const char*xx, void *yy){
                this->on_test_handler(xx, yy);
            },
            (void*)"444456"
        );
        // GHI
        _a1.regist_handler(
            "GHI",
            [this](const char*xx, void *yy){
                this->on_test_handler(xx, yy);
            },
            (void*)"777789"
        );
        // abc
        CallbackWrapper::broker_func  = std::bind(&B::on_test_handler, this, std::placeholders::_1, std::placeholders::_2);
        _a2.regist_handler(
            "abc",
            CallbackWrapper::wrapper_func,
            (void*)"123"
        );
        // def
        CallbackWrapper::broker_func  = std::bind(&B::on_test_handler, this, std::placeholders::_1, std::placeholders::_2);
        _a2.regist_handler(
            "def",
            CallbackWrapper::wrapper_func,
            (void*)"456"
        );
        // ghi
        CallbackWrapper::broker_func  = std::bind(&B::on_test_handler, this, std::placeholders::_1, std::placeholders::_2);
        _a2.regist_handler(
            "ghi",
            CallbackWrapper::wrapper_func,
            (void*)"789"
        );
    }
    void send(const char* x) {
        _a1.send(x);
    }
private:
    A1 _a1; // callback for own server
    A2 _a2; // callback for c server
};

// ============================================================================
// g++ *.cpp -std=c++17 -o main
int main(int argc, const char* argv[]) {
    std::cout << "Hello World!" << std::endl;
    
    B b;
    b.init();
    
    // lambda function with this to stl-function-style callback function
    b.send("ABC");
    b.send("DEF");
    b.send("GHI");

    //  class member function to c-style callback function
    g_send("abc");
    g_send("def");
    g_send("ghi");

    return 0;
}
// ============================================================================

上述代码在注册不同成员函数时会出现bug(仅注册成功最后一个成员函数指针),与执行回调函数的时机有关,遂作如下改动即可避免该问题:

#include <iostream>
#include <functional>
#include <vector>
using namespace std;

class CallbackWrapper {
public:
    static auto get_current_function(size_t i) {
        cout << "get_current_function_index=" << i << endl;
        return broker_func[i];
    }
    // g++ -std=c++17
    static void add_function_obj(std::function<void(int* xx, int* yy)> func) {
        broker_func.push_back(func);
        cout << "broker_func.size=" << broker_func.size() << endl;
    }
private:
    inline static vector<std::function<void(int* xx, int* yy)>> broker_func;
};

class regist {
public:
    typedef void(*func_callback)(int*, int*);
    regist() = default;
    ~regist() = default;
    void do_regist(func_callback func) {
        cout << "do_regist &func=  " << &func << endl;
        fs.push_back(func);
    }
    vector<func_callback> fs;
};

class test {
public:
    test(/* args */) = default;
    ~test() = default;
    void demo1(int* a, int* b) {
        cout << "demo1: " << *a << " , " << *b << endl;
    }
    void demo2(int* a, int* b) {
        cout << "demo2: " << *a << " , " << *b << endl;
    }
    void init() {
        CallbackWrapper::add_function_obj(std::bind(
            &test::demo1, this, 
            std::placeholders::_1, std::placeholders::_2
        ));
        r.do_regist([](int* x, int* y){
            CallbackWrapper::get_current_function(0)(x, y);
        });

        CallbackWrapper::add_function_obj(std::bind(
            &test::demo2, this, 
            std::placeholders::_1, std::placeholders::_2
        ));
        r.do_regist([](int* x, int* y){
            CallbackWrapper::get_current_function(1)(x, y);
        });
    }
    regist r;
};

int main() {
    test t;
    t.init();
    int a = 12, b = 13, c = 14;
    t.r.fs[0](&a, &b);
    t.r.fs[1](&b, &c);
    return 0;
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值