10

所以,我正在使用 FMOD api,它确实是一个 C api。

并不是说这很糟糕或任何事情。只是它与 C++ 代码的接口不好。

例如,使用

FMOD_Channel_SetCallback( channel, callbackFunc ) ;

它需要一个 C 风格的函数callbackFunc,但我想将一个类的成员函数传递给它。

我最终为此使用了 Win32 技巧,使成员函数成为静态的。然后它作为 FMOD 的回调。

现在我必须破解我的代码以使一些成员静态,只是为了说明 FMOD 的 C 特性。

我想知道它在 FMOD 中是否可行,或者是否有办法将回调链接到特定 C++ 对象的实例成员函数(不是静态函数)。会顺畅很多。

4

5 回答 5

12

您不能直接传递成员函数。成员函数具有隐式参数this,而 C 函数则没有。

你需要创建一个蹦床(不确定回调的签名,所以在这里做一些随机的事情)。

extern "C" int fmod_callback( ... args ...)
{
    return object->member();
}

一个问题是该对象指针从何而来。希望 fmod 为您提供一个通用的上下文值,当您进行回调时将提供给您(然后您可以传入对象指针)。

如果没有,您只需将其设为全局即可访问它。

于 2010-03-10T20:36:46.867 回答
5

我想它应该像这样工作:
您可以通过调用将一些用户数据分配给通道FMOD_Channel_SetUserData。此用户数据应该是指向处理事件的 C++ 对象的指针。然后,您应该编写 C 风格的回调,通过调用提取该对象FMOD_Channel_GetUserData,然后在该对象上调用您的 C++ 实例方法。

于 2010-03-10T21:04:57.633 回答
2

有一个不可移植且相当老套的解决方案,其优点是至少是线程安全的,而“蹦床”方法则不是。

您可以即时生成实际的功能机器代码。基本思想是,您有一个回调函数模板,该模板接受一个对象指针和一个成员函数指针,并为您提供一块堆内存,您可以将其作为 C 回调函数传递给库,即将在被调用时转身并调用该对象上的成员函数。

它很混乱,你必须为任何新平台提供一个实现(任何时候调用约定发生变化),但它可以工作,是线程安全的。(当然,您还必须注意 DEP)。另一个线程安全的解决方案是使用线程本地存储(假设您知道回调将发生在与您进行的调用相同的线程上)。

有关如何生成 thunk 的示例,请参阅http://www.codeproject.com/KB/cpp/GenericThunks.aspx 。

于 2010-03-10T21:09:59.820 回答
1

在我的拙见中,仅对 C 回调使用函数指针(并且没有额外的单独对象指针)是一个错误的设计。

相反,如果函数是 ,FMOD_Channel_SetCallback(channel, callbackFunc, callbackObj)那么您的静态方法只需要对象的一个​​实例,然后调用callbackObj->func()(这显然可以是非静态的)。

于 2010-03-10T20:36:01.167 回答
0

您需要使用蹦床并将指针存储到要在全局或静态变量中调用成员函数的对象,即

Object *x;
void callback_trampoline() { x->foobar(); }
...
FMOD_Channel_SetCallback(CHANNEL, callback_trampoline);
于 2010-03-10T20:38:28.917 回答