【问题标题】:Using an object method as a function callback使用对象方法作为函数回调
【发布时间】:2011-06-23 15:14:38
【问题描述】:

我正在使用具有回调函数的 C 库,例如:

int DownloadStream(LPCTSTR  host,DWORD channelNumber,NewImage pNewImage);
typedef int  (*NewImage)(BYTE *pData, int nLen,void *returnHandle);

在 C 中我可以这样调用:

int  CallDownloadStream(LPCTSTR  host,DWORD channelNumber)
{

  int hr = DownloadStream(host,channelNumber,OnNewImage);

  return hr;

}


int OnNewImage(BYTE *pData, int nLen,void *returnHandle)
{

   // able to get data

}

我想要的是将这些函数称为 C++ 类的成员,例如:

class MyClass
{

public:


   int  CallDownloadStream(LPCTSTR  host,DWORD channelNumber)
   {

       int hr = DownloadStream(host,channelNumber,OnNewImag);

       return hr;
   }

   int OnNewImage(BYTE *pData, int nLen,void *returnHandle)
   {

   // able to get data

   }
}

我无法编译它。是否可以以这种方式使用这些回调函数?如果可以,怎么做?

PS:我无法控制原始 C 风格的回调函数。

【问题讨论】:

  • 什么是 void *returnHandle ?是否有另一个功能可以让您将其值设置为您想要的任何值?它可用于将实例传递给您的类,并在调用回调时将其取回。
  • 这是一个特定 API 函数的特性...与类实例无关。

标签: c++ c callback


【解决方案1】:

无法完成。如果 C 函数不提供用户提供的参数指针,这在 C 中惯用的,那么你不能这样做。

编辑:这严格不正确。您可以使用静态变量,可以使用线程本地存储,也可以 JIT 函数。但是,这些不是一般情况下的解决方案。

【讨论】:

  • 什么是用户提供的参数指针?实际上,某些 API 有一些参数,例如“void *pUser”,它表示“传输回调函数的变量”。可以是用户提供的参数指针吗?
  • @6.45.Vapuru:用户提供的参数指针是您向 API 传递一个指针的地方,然后它会在不修改的情况下传递您的回调 - 有效地允许您传递“this”。但是这些函数表明他们不这样做。
  • 是对的。 可能 起作用的一个讨厌的 hack - 取决于您的确切用法 - 是将 this 指针存储在一些全局可访问的变量中 - 可能在以其他状态数据为键的映射中。如果您可能注册了多个实例并且与另一个状态没有一对一的对应关系,那么这就会崩溃,但这是您在这种情况下可以做的最好的事情。
【解决方案2】:

您正在做的是传递一个函数指针,以便 C 函数可以调用它。换句话说,你传递的函数指针必须可以从 C 中调用。这意味着它必须是extern "C",并且不能是典型的成员函数。它可以是static 成员函数,也可以是独立函数,但不能是类成员函数。

这意味着回调函数不能影响类数据成员。它可以影响静态成员数据、全局数据或其他任何数据,但不会影响类成员数据。如果这是您正在寻找的效果,您需要提供某种非类缓冲区并自己移动数据。

这也意味着传递的函数不能是多态的。如果您想要多态行为,则需要将所有要传递的回调函数定义为static 或在任何类之外,并在多态函数中调用库函数。

【讨论】:

    【解决方案3】:

    您不能将非静态成员函数用作 C 回调函数。

    所以答案是使用静态成员函数。

    【讨论】:

    • 通常是一个公共成员friend void __stdcall CallBack(Data* pData),它在传入的数据结构中使用“自我”指针来调用类
    • 他不提供 pData 参数,库提供。
    • -1:静态方法没有 this 指针,即使回调中使用了该参数。
    • 是的。 pData由图书馆提供
    • 使用静态成员函数可能适用于 Visual C++(我没有检查过最新版本),但对于其他一些编译器和正式的静态成员函数不能直接用作回调,因为正式的回调需要是extern "C"。而且您不能将其应用于静态成员函数。令人高兴的是,这个问题已经在 Usenet 上讨论过很多次,而且我记得没有编译器至少不能为您提供一些方法来告诉它闭嘴并做到这一点。 :-)
    【解决方案4】:

    可能能够使用 libsigc++ - http://libsigc.sourceforge.net/(查看 mem_fun 的文档)。我不确切知道需要什么才能使其正常工作。或者,创建一个 C 回调函数,它使用指向对象的指针简单地调用正确的 C++ 函数。 (这可能是最简单的方法)

    【讨论】:

    • 好吧,我不想破解。 C/C++ 已经够复杂了……不需要再复杂了:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 2014-02-10
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多