【问题标题】:how to pass a non static-member function as a callback?如何将非静态成员函数作为回调传递?
【发布时间】:2011-01-07 01:14:32
【问题描述】:

 
io_iterator_t enumerator;
kern_return_t   result;
result = IOServiceAddMatchingNotification(
             mNotifyPort,
             kIOMatchedNotification,
             IOServiceMatching( "IOFireWireLocalNode" ),
             serviceMatchingCallback, 
             (void *)0x1234,
             & enumerator );

serviceMatchingCallback((void *)0x1234, enumerator);

如果我将 serviceMatchinCallback 声明为静态,那么它可以工作,但我不希望它是静态的。有没有办法给它传递一个非静态回调函数?

谢谢

【问题讨论】:

  • 你应该把标签从 c 改成 c++
  • 您使用的是 C、C++ 还是 Objective-C?
  • 是的,我应该提到它,它的 c++
  • @Martin:ISTR IOKit 示例驱动程序使用静态函数作为回调,所以也许可以保证这里有相同的链接。但是,是的,2068022 更通用。

标签: c++ function callback member non-static


【解决方案1】:

IOServiceMatchingCallback 的原型与非静态类方法(技术上是 not compatible with a static class method either)不兼容,因此您将无法使用它。

但幸运的是 IOServiceAddMatchingNotification 支持上下文指针(或者他们称之为 refCon),这将允许您创建不依赖于全局数据的 thunk。

您需要定义具有兼容链接的回调(即 extern "C")。此函数会将您的 refCon 转换为您的对象指针,然后将调用转发给您的实例方法:

extern "C"
void io_callback(void *refcon, io_iterator_t iterator)
{
    myclass *c = static_cast<myclass *>(refcon);
    c->real_callback(iterator);
}

然后,当您调用 IOServiceAddMatchingNotification 时,请确保为 refCon 传递一个指向您的对象的指针(这里我假设您从成员函数调用 IOServiceAddMatchingNotification 并且您有一个 this 指针):

result = IOServiceAddMatchingNotification(
             mNotifyPort,
             kIOMatchedNotification,
             IOServiceMatching( "IOFireWireLocalNode" ),
             serviceMatchingCallback, 
             this,
             &enumerator );

【讨论】:

【解决方案2】:

您可以将其保持为静态,但使用 userdata 来存储 this 指针以及您想要的任何其他用户数据(例如,通过将它们打包到一个结构中),然后从静态调用特定于对象的回调版本通过调用this-&gt;someCallback (其中this 是存储在用户数据中的指针,当然)。

【讨论】:

    【解决方案3】:

    不直接。

    非静态函数指针(称为成员函数指针)有一个隐藏的“this”参数,因此类型不匹配。静态函数没有“this”指针。

    要解决这个问题,您需要能够传入一个用户数据项,它是您想要用作回调的对象的“this”指针。然后,指定一个传递用户数据的静态成员,将其转换为指向类对象的指针,并在其上调用非静态成员。

    查看您发布的代码,很难判断是否存在用户数据对象,可能是 last-but=one 参数。

    【讨论】:

      【解决方案4】:

      不,非静态成员需要一个对象,而调用者(call-backer)没有也不会提供。

      【讨论】:

        【解决方案5】:

        没有。非静态方法需要一个对象来操作。如果你只是传递方法,你还需要一些方法来告诉函数调用哪个对象的方法。

        【讨论】:

          【解决方案6】:

          static 函数具有隐式this 参数,因此回调的签名错误。

          抱歉,没有简单的方法可以避开跳跃岛。

          【讨论】:

          • 但是我在静态成员方法 serviceMatchingCallback(...) 中使用的成员变量也应该是静态的。静态成员变量必须在顶部声明,这是我不想要的。如果我错了,请纠正我。
          • 我无法解析您的回复,因为成员只能在类声明中声明。我也不知道“必须在顶部声明静态成员变量”是什么意思。 (最重要的是什么?类?源文件?)在这一点上,我将简单地向您指出 R Samuel Klatchko 在上面的更完整的答案。
          【解决方案7】:

          如果你把这一行放在你的构造函数中(或任何实例方法中),那么你应该能够执行 this.instanceMethod() 来引用实例方法。

          【讨论】:

            【解决方案8】:

            编辑 我刚刚注意到您使用的是用户空间 IOKit API,而不是 kext 端,这使得这篇文章无关紧要。


            假设您在 OS X 内核中工作,您实际上可以做到这一点。 您可以使用OSMemberFunctionCast 宏将成员函数指针转换为普通的 C 函数指针,请注意它应该在第一个参数指向类的实例的情况下调用,例如。

            IOServiceMatchingCallback mycb = OSMemberFunctionCast(IOServiceMatchingCallback,
                &myclassinstance, &MyClass::cb_method);
            
            result = IOServiceAddMatchingNotification(
                         mNotifyPort,
                         kIOMatchedNotification,
                         IOServiceMatching( "IOFireWireLocalNode" ),
                         mycb,
                         &myclassinstance,
                         &enumerator);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2018-09-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-04-14
              • 2020-12-31
              相关资源
              最近更新 更多