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

RRR*_*RRR 21 c c++ pointers function-pointers

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

这是我的班级:

 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(); 
};
Run Code Online (Sandbox Code Playgroud)

这是我的on_btn_clicked函数:

void MainWindow::on_btn_clicked()
{
    void (MainWindow::* ptfptr) (int*) = &MainWindow::f;

    c_library_function(static_cast<void()(int*)>(ptfptr), NULL);

}
Run Code Online (Sandbox Code Playgroud)

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

有人可以帮忙吗?

Tri*_*dle 22

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

但是,你可以(通常)通过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 */);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后将您的回调注册为

c_library_function(MyClass::static_func, this);
Run Code Online (Sandbox Code Playgroud)

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

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


Snp*_*nps 15

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

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

template <typename T>
struct Callback;

template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
    template <typename... Args>
    static Ret callback(Args... args) { return func(args...); }
    static std::function<Ret(Params...)> func;
};

// Initialize the static member.
template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;
Run Code Online (Sandbox Code Playgroud)

使用它可以存储任何可调用的,甚至是非静态成员函数(使用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<void(int*)>::func = std::bind(&Foo::print, foo, std::placeholders::_1);

    // Convert callback-function to c-pointer.
    void (*c_func)(int*) = static_cast<decltype(c_func)>(Callback<void(int*)>::callback);

    // Use in any way you wish.
    std::unique_ptr<int> iptr{new int(5)};
    c_func(iptr.get());
}
Run Code Online (Sandbox Code Playgroud)


Fer*_*eak 11

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

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


Tho*_*ser 5

@Snps的答案很好。我使用创建回调的maker函数对其进行了扩展,因为我始终使用void不带参数的回调:

typedef void (*voidCCallback)();
template<typename T>
voidCCallback makeCCallback(void (T::*method)(),T* r){
  Callback<void()>::func = std::bind(method, r);
  void (*c_function_pointer)() = static_cast<decltype(c_function_pointer)>(Callback<void()>::callback);
  return c_function_pointer;
}
Run Code Online (Sandbox Code Playgroud)

从那时起,您可以在类内或其他任何位置创建纯C回调,并将成员称为:

voidCCallback callback = makeCCallback(&Foo::print, this);
plainOldCFunction(callback);
Run Code Online (Sandbox Code Playgroud)