将C ++函数指针转换为c函数指针

我正在使用C库开发C ++应用程序。 我必须向C库发送一个函数指针。

这是我的class级:

class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); private: Ui::MainWindow *ui; void f(int*); private slots: void on_btn_clicked(); }; 

这是我的on_btn_clicked函数:

 void MainWindow::on_btn_clicked() { void (MainWindow::* ptfptr) (int*) = &MainWindow::f; c_library_function(static_cast(ptfptr), NULL); } 

C函数应该得到一个指向这样一个函数的指针:void f(int *)。 但上面的代码不起作用,我无法成功将我的f成员函数转换为所需的指针。

有人可以帮忙吗?

如果我没记错,只能通过函数语法的“普通”C指针访问类的静态方法。 所以尽量让它变得静止。 指向类方法的指针需要额外的信息,例如“对象”(this),它对纯C方法没有意义。

此处显示的常见问题解答有很好的解释和可能(丑陋)的解决方案。

您不能将非静态成员函数指针作为普通函数指针传递。 它们不是一回事,甚至可能都不一样。

但是,你可以(通常)通过C传递指向静态成员函数的指针。通常在C API中注册回调时,你也可以传递一个“用户数据”指针,该指针会被传递回你的注册函数。 所以你可以这样做:

 class MyClass { void non_static_func(/* args */); public: static void static_func(MyClass *ptr, /* other args */) { ptr->non_static_func(/* other args */); } }; 

然后将您的回调注册为

 c_library_function(MyClass::static_func, this); 

即将实例指针传递给静态方法,并将其用作转发函数。

严格来说,为了完全可移植性,您需要使用声明为extern "C"的自由函数而不是静态成员来进行转发(必要时声明为friend ),但实际上我使用此方法接口时从未遇到任何问题带有GObject代码的C ++代码,它是C回调重的。

您不能将函数指针传递给非静态成员函数。 您可以做的是创建一个静态或全局函数,使用实例参数进行调用。

这是一个我觉得有用的例子,它使用一个带有两个成员的辅助类:一个函数包装器和一个调用包装器的回调函数。

 template  struct Callback; template  struct Callback { template  static Ret callback(Args... args) { return func(args...); } static std::function func; }; // Initialize the static member. template  std::function Callback::func; 

使用它,您可以存储任何可调用的,甚至非静态成员函数(使用std::bind )并使用Callback::callback函数转换为c指针。 例如:

 struct Foo { void print(int* x) { // Some member function. std::cout << *x << std::endl; } }; int main() { Foo foo; // Create instance of Foo. // Store member function and the instance using std::bind. Callback::func = std::bind(&Foo::print, foo, std::placeholders::_1); // Convert callback-function to c-pointer. void (*c_func)(int*) = static_cast(Callback::callback); // Use in any way you wish. std::unique_ptr iptr{new int(5)}; c_func(iptr.get()); } 

@Snps答案很棒。 我用一个创建回调的制造商函数扩展它,因为我总是使用没有参数的void回调:

 typedef void (*voidCCallback)(); template voidCCallback makeCCallback(void (T::*method)(),T* r){ Callback::func = std::bind(method, r); void (*c_function_pointer)() = static_cast(Callback::callback); return c_function_pointer; } 

从那时起,您可以在类或其他任何地方创建纯C回调,并将成员调用:

 voidCCallback callback = makeCCallback(&Foo::print, this); plainOldCFunction(callback); 

我有一个想法(不完全符合标准,因为extern "C"缺失):

 class MainWindow; static MainWindow* instance; class MainWindow { public: MainWindow() { instance = this; registerCallback([](int* arg){instance->...}); } }; 

如果实例化多个MainWindow实例,您将遇到问题。

简短的回答是:您可以使用std :: mem_fn将成员函数指针转换为普通的C函数指针。

这就是给定问题的答案,但这个问题似乎有一个混乱的前提,因为提问者希望C代码能够在没有MainWindow *的情况下调用MainWindow的实例方法,这根本不可能。

如果使用mem_fn将MainWindow::on_btn_clicked转换为C函数指针,那么您仍然是一个以MainWindow*作为其第一个参数的函数。

 void (*window_callback)(MainWindow*,int*) = std::mem_fn(&MainWindow::on_btn_clicked); 

这是给出的问题的答案,但它与界面不匹配。 您必须编写一个C函数来将调用包装到特定实例(毕竟,您的C API代码对MainWindow或其任何特定实例一无所知):

 void window_button_click_wrapper(int* arg) { MainWindow::inst()->on_btn_clicked(arg); } 

这被认为是OO反模式,但由于C API对您的对象一无所知,因此这是唯一的方法。

@Snps答案很完美! 但正如@DXM提到的,它只能保留一个回调。 我已经改进了一点,现在它可以保留很多相同类型的回调。 这有点奇怪,但完美无缺:

  #include  template struct ActualType { typedef T type; }; template struct ActualType { typedef typename ActualType::type type; }; template struct Callback; template struct Callback { typedef Ret (*ret_cb)(Params...); template static Ret callback(Args ... args) { func(args...); } static ret_cb getCallback(std::function fn) { func = fn; return static_cast(Callback::callback); } static std::function func; }; template std::function Callback::func; #define GETCB(ptrtype,callertype) Callback::type,__COUNTER__,callertype>::getCallback 

现在你可以做这样的事情:

 typedef void (cb_type)(uint8_t, uint8_t); class testfunc { public: void test(int x) { std::cout << "in testfunc.test " <