关于c ++:如何将非静态成员函数作为回调传递?

how to pass a non static-member function as a callback?

1
2
3
4
5
6
7
8
9
io_iterator_t enumerator;
kern_return_t   result;
result = IOServiceAddMatchingNotification(
             mNotifyPort,
             kIOMatchedNotification,
             IOServiceMatching("IOFireWireLocalNode" ),
             serviceMatchingCallback,
             (void *)0x1234,
             & enumerator );

<规范>

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

<规范>

如果我servicematchincallback然后它声明为静态的,但我不希望它是静态的。有没有办法通过它一个非静态回调函数?

谢谢你


ioServiceMatchingCallback的原型与非静态类方法不兼容(并且在技术上也与静态类方法不兼容),因此您将无法使用该方法。

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

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

1
2
3
4
5
6
extern"C"
void io_callback(void *refcon, io_iterator_t iterator)
{
    myclass *c = static_cast<myclass *>(refcon);
    c->real_callback(iterator);
}

然后,当您调用ioServiceAddMatchingNotification时,请确保向对象传递一个指针以进行refcon(这里假设您从成员函数调用ioServiceAddMatchingNotification,并且您有一个此指针):

1
2
3
4
5
6
7
result = IOServiceAddMatchingNotification(
             mNotifyPort,
             kIOMatchedNotification,
             IOServiceMatching("IOFireWireLocalNode" ),
             serviceMatchingCallback,
             this,
             &enumerator );


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


不是直接的。

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

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

查看您发布的代码,很难判断是否有用户数据对象,可能是最后一个,但=一个参数。


编辑我刚刚注意到您使用的是用户空间iokit api,而不是kext端,这使得本文不相关。

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

1
2
3
4
5
6
7
8
9
10
IOServiceMatchingCallback mycb = OSMemberFunctionCast(IOServiceMatchingCallback,
    &myclassinstance, &MyClass::cb_method);

result = IOServiceAddMatchingNotification(
             mNotifyPort,
             kIOMatchedNotification,
             IOServiceMatching("IOFireWireLocalNode" ),
             mycb,
             &myclassinstance,
             &enumerator);

如果将此行放入构造函数(或任何实例方法)中,则应该能够执行此操作。InstanceMethod()以引用实例方法。


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

对不起,要避开跳岛可不容易。


不是。非静态方法需要一个对象来操作。如果只传递方法,还需要某种方法来告诉函数调用方法的对象。


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