且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用C ++类的成员函数(不能是静态)为C回调函数

更新时间:2022-10-16 18:30:27

这是不可能的,至少与 handler_t 签名。

虽然您可以创建你的.cpp一个免费的功能来包装成员通话,您需要一个指向实例:

 无效my_wrap(INT富,无效*吧){
    美孚* some_foo_instance = ...;
    some_foo_instance->处理器(富,吧);
}INT主(INT ARGC,字符** argv的){
    set_handler(安培; my_wrap);
}

您需要一些无效*传递实例作为处理程序属性:

  //头
无效的typedef(* handler_t)(INT富,无效*酒吧,无效* ARG1);
无效set_handler(handler_t小时,无效* ARG1);//默认地将Impl。
无效set_handler(handler_t小时,无效* ARG1){
        handler_ = H;
        handler_arg1_ = ARG1;
}// CPP
无效my_wrap(INT富,无效*酒吧,无效* ARG1){
    美孚* some_foo_instance =的static_cast<富*>(ARG1);
    some_foo_instance->处理器(富,吧);
}//主
INT主(INT ARGC,字符** argv的){
    富some_concrete_instance;
    set_handler(安培; my_wrap,与的static_cast LT;无效*>(安培; some_concrete_instance));
}

I have a C library function that expects a function pointer for callback, and I want to pass in a C++ member function. The C++ function modifies a member variable, so I can't use a static free function (as suggested in several similar posts). My attempt (shown below) fails with a compiler error.

This post comes closest to what I need:

Using a C++ class member function as a C callback function

How can I do this without static functions? Thanks!


test.h

#ifndef TEST_H_
#define TEST_H_

#ifdef __cplusplus
extern "C" {
#endif

typedef void (*handler_t)(int foo, void *bar);

void set_handler(handler_t h);

#ifdef __cplusplus
}
#endif

#endif


test.c

#include "test.h"
#include <stdlib.h>

static handler_t handler_ = NULL;
void set_handler(handler_t h) {
        handler_ = h;
}

void handle_event(int foo, void *bar) {
        if (handler_ != NULL) handler_(foo, bar);
}


test.cpp

#include "test.h"
#include <iostream>
using namespace std;

class Foo {
public:
        Foo() : ctr_(0) {};

        // handler needs to access non-static variable, so it can't be static
        void handler(int foo, void *bar) { ++ctr_;  }

private:
        int ctr_;
};

int main(int argc, char **argv) {
        // error: can't convert to "void (*)(int, void*)"
        set_handler(&Foo::handler);

        cout << "done" << endl;
        return 0;
}


GCC barf

$ gcc test.cpp test.c 
test.cpp: In function ‘int main(int, char**)’: 
test.cpp:18: error: cannot convert ‘void (Foo::*)(int, void*)’ to ‘void (*)(int, void*)’ for argument ‘1’ to ‘void set_handler(void (*)(int, void*))’

It is not possible, at least with that handler_t signature.

While you can create a free function on your .cpp to wrap the member call, you need a pointer to the Foo instance:

void my_wrap(int foo, void* bar) {
    Foo* some_foo_instance = ...;
    some_foo_instance->handler(foo, bar);
}

int main(int argc, char **argv) {
    set_handler(&my_wrap);
}

You need some void* to pass the Foo instance as a handler attribute:

// Header
typedef void (*handler_t)(int foo, void *bar, void* arg1);
void set_handler(handler_t h, void* arg1);

// Impl.
void set_handler(handler_t h, void* arg1) {
        handler_ = h;
        handler_arg1_ = arg1;
}

// cpp
void my_wrap(int foo, void* bar, void* arg1) {
    Foo* some_foo_instance = static_cast<Foo*>(arg1);
    some_foo_instance->handler(foo, bar);
}

// main
int main(int argc, char **argv) {
    Foo some_concrete_instance;
    set_handler(&my_wrap, static_cast<void*>(&some_concrete_instance));
}