函数指针指向类成员函数问题

时间:2009-01-13 16:01:39

标签: c++ pointers function-pointers

首先,我必须承认我的编程技巧非常有限,我接手了一个(非常小的)现有的C ++ OOP项目,我试图将自己的东西推进去。不幸的是,我遇到的问题超出了我的知识,我希望在这里找到一些帮助。我正在使用第三方库(无法更改)从相机中抓取图像,并在此处使用一些占位符名称。

第三方库有一个函数“ThirdPartyGrab”来启动连续实时抓取,并获取一个指向函数的指针,该函数将在每次新帧到达时调用。所以在正常的C应用程序中它是这样的:

ThirdPartyGrab (HookFunction);

“HookFunction”需要声明为:

long _stdcall HookFunction (long, long, void*);

或“BUF_HOOK_FUNCTION_PTR”,声明为

typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);

现在我有一个C ++应用程序和一个类“MyFrameGrabber”,它应该封装我所做的一切。所以我将钩子函数作为私有成员放入这样的:

long _stdcall HookFunction (long, long, void*);

我班上还有一个公共无效功能“StartGrab”应该启动Grab。在里面我试着打电话:

ThirdPartyGrab (..., HookFunction, ...);

(毫不奇怪)失败了。它说对MyFrameGrabber :: HookFunction的函数调用错过了参数列表,我应该尝试使用& MyFrameGrabber :: HookFunction来创建指针。但是,传递“& MyFrameGrabber :: HookFunction”会导致另一个错误,即无法将其转换为BUF_HOOK_FUNCTION_PTR。

阅读C++ FAQ function pointers之后我认为我理解了这个问题,但无法解决问题。我试图使钩子函数静态,但这也导致转换错误。我还想过把钩子函数放在类之外,但我需要在钩子函数中使用类函数。还有其他方式还是我需要改变我的整个概念?

编辑14.01.08: 我测试了单例解决方法,因为我无法更改第三方库,而void指针仅用于在钩子函数内部使用的数据。不幸的是它并没有像我希望的那样开箱即用....我不知道静态函数是否需要在一个单独的类中,所以我把它放在我的“MyFrameGrabber”类中:

static MyFrameGrabber& instance()
{
        static MyFrameGrabber _instance;
        return _instance;
}
long Hook(long, long, void*); // Implementation is in a separate cpp file

在我的cpp文件中,我有call_hook函数:

long MFTYPE call_hook(long x, MIL_ID y, void MPTYPE *z)
{
    return MyFrameGrabber::instance().Hook(x,y,z);
}
void
MyFrameGrabber::grab ()
{
    ThirdPartyGrab(..., call_hook, ...);
}

但是这在static MatroxFrameGrabber _instance;中给出了一个错误,即找不到匹配的标准构造函数。这是正确的,因为我的MyFrameGrabber构造函数看起来像这样:

MyFrameGrabber (void* x,
                const std::string &y, int z,
                std::string &zz);

我尝试放入一个空构造函数MyFrameGrabber();,但这会导致链接器错误。我应该将空参数传递给单例中的MyFrameGrabber构造函数吗?或者我需要一个单独的Hook类,如果是,我怎么能访问MyFrameGrabber函数?提前致谢。

第二次编辑15.01.08: 我应用了更改,现在编译和链接。不幸的是我无法在运行时测试它,因为它是一个DLL,我还没有Debug Caller Exe,并且在初始化期间还有其他问题。我会将帖子标记为答案,因为我确信这是正确的方法。

2 个答案:

答案 0 :(得分:7)

您的私有成员方法有一个隐式this指针作为第一个参数。如果你写出来,很明显函数签名不匹配。

您需要编写一个静态成员函数,该函数可以作为回调函数传递给库。 HookFunction的最后一个参数void*在我看来非常像一个cookie,在那里可以传递自己的指针。

所以,总而言之,它应该是这样的:

class MyClass {
  long MyCallback(long, long) {
    // implement your callback code here
  }

  static long __stdcall ThirdPartyGrabCallback(long a, long b, void* self) {
    return reinterpret_cast<MyClass*>(self)->MyCallback(a, b);
  }
public:
  void StartGrab() {
    ThirdPartyGrab(..., &MyClass::ThirdPartyGrabCallback, ..., this, ...);
  }
};

这当然只有在void*论证正在按我说的做的时候才有效。当拥有包含可用参数名称的完整函数签名时,this调用中ThirdPartyGrab()的位置应该很容易找到。

答案 1 :(得分:2)

“&amp; MyFrameGrabber :: HookFunction”无法转换为BUF_HOOK_FUNCTION_PTR的原因是,作为该类的成员,它隐式地将第一个参数作为“this”指针,因此您无法将成员函数转换为非成员函数:两个签名看起来相同,但实际上是不同的。

我会声明一个接口,定义要调用的函数,让您的类实现它并传递对象本身而不是回调(您可以将接口视为面向对象的函数指针替换):

class IHookInterface{
public:
    virtual long HookFunction(long, long, void*) = 0;
};
 class HookClass : public IHookInterface{
public:
    virtual long Hook(long, long, void*) {
        // your code here... 
    }
};

//新定义: ThirdPartyGrab(...,IHookInterface,...);

编辑 - 其他可能的解决方案,以防您无法修改库:使用单例而不是静态函数。

class HookClass{
public:
    static HookClass& instance(){
        static HookClass _instance;
        return _instance;
    }
    long Hook(long, long, void*) {
        // your code here... 
    }
};

long call_hook(long x,long y,void * z){
    return HookClass::instance().Hook(x,y,z);
}

SECOND EDIT:您可能会使用初始化方法稍微修改单例类,以使用适当的参数调用构造函数,但是它可能不比以下解决方案更优雅,这更简单:

class HookClass{
public:

    HookClass(string x,string y...){
    }

    long Hook(long, long, void*) {
        // your code here... 
    }
};

static HookClass * hook_instance = 0;

long call_hook(long x,long y,void * z){
    if (0 != hook_instance){
        return hook_instance->Hook(x,y,z);
    }
}

int main(){
    hook_instance = new HookClass("x","y");
    ThirdPartyGrab(..., call_hook, ...);
}
相关问题