在 C++ 类中访问 C 风格的回调

Posted

技术标签:

【中文标题】在 C++ 类中访问 C 风格的回调【英文标题】:Accessing C-style callbacks inside C++ class 【发布时间】:2018-09-28 10:03:00 【问题描述】:

以下 C 风格的 API 函数由 PiGPIO 库提供:

typedef void (*gpioAlertFuncEx_t)(int, int, uint32_t, void *);  // assumed  
int gpiosetAlertFuncEx(unsigned user_gpio, gpioAlertFuncEx_t f, void *userdata)

基本上,它允许您通过回调函数处理引脚状态更改。

到目前为止一切顺利。问题是将此回调包装到 c++ 类中。

我的方法如下:

class Pin

public:
    Pin(_GpioPin)
    
        gpioSetAlertFuncEx(_GpioPin, &PushButton::internal_gpio_callback, this );
    

    void internal_callback_func(int pin, int level, uint32_t tick)
    
        cout << "New level: " << pin << " " << level;
    

问题在于回调函数类型不同(因为它是非静态的)。并提示错误:

 error: cannot convert 'void (Pin::*)(int, int, uint32_t, void*) aka void (Pin::*)(int, int, unsigned int, void*)' to 'gpioAlertFuncEx_t aka void (*)(int, int, unsigned int, void*)' for argument '2' to 'int gpioSetAlertFuncEx(unsigned int, gpioAlertFuncEx_t, void*)'
  gpioSetAlertFuncEx(this->GpioPin, &Pin::internal_gpio_callback), this );

有什么诀窍?如何投射&amp;PushButton::internal_gpio_callback 以匹配所需的模板?

稍后编辑:我不想将回调方法设为静态。

【问题讨论】:

typedef void(*gpioAlertFuncEx_t) (int gpio, int level, uint32_t tick, void *userdata) 是我在谷歌搜索该类型名称时得到的。 void* 您的版本丢失是有意义的。为什么放弃void* 您是否尝试将 internal_callback_func 声明为静态?指向类方法的指针没有得到很好的解释。 @KarolT。抱歉,我忘了提到我需要该方法不是静态的 请注意,您显示的代码不适合,名称和符号冲突,并且与错误消息也不匹配。创建Minimal, Complete, and Verifiable Example 时,请确保它确实完整且可验证。 @Yakk-AdamNevraumont 好的,这是我在提取相关代码时的错误。 【参考方案1】:

指向成员函数的指针与指向非成员函数的指针不同。不同之处在于成员函数需要调用一个对象,这是 C 无法处理的。

有一些方法可以解决这个问题,尤其是在您已经将 this 作为 userdata 指针传递的情况下。解决方案是简单地将真正的成员函数包装在 static 成员函数中(因为它们可以作为 C 回调函数传递)。

例如:

class Pin

public:
    Pin(_GpioPin)
    
        gpioSetAlertFuncEx(_GpioPin, &Pin::static_internal_callback_func, this );
    

private:
    static void static_internal_callback_func(int pin, int level, uint32_t tick, void* userdata)
    
        static_cast<Pin*>(userdata)->internal_callback_func(pin, level, tick);
    

    void internal_callback_func(int pin, int level, uint32_t tick)
    
        cout << "New level: " << pin << " " << level;
    
;

【讨论】:

以上是关于在 C++ 类中访问 C 风格的回调的主要内容,如果未能解决你的问题,请参考以下文章

Item 43:访问模板基类中的名称 Effective C++笔记

运行回调时无法访问 JS 类中的函数

C ++:如何访问另一个类中的类函数?

在类中访问结构对象变量 - C++

小白学习C++ 教程十一C++类中访问修饰符

从基类派生类中 C++ 向量的可访问性