asd*_*ael 5 c++ pointers function-pointers
首先,我必须承认我的编程技巧非常有限,我接手了一个(非常小的)现有的C++ OOP项目,我尝试将自己的东西推进去.不幸的是,我遇到的问题超出了我的知识范围.我希望在这里找到一些帮助.我正在使用第三方库(无法更改)从相机中抓取图像,并在此处使用一些占位符名称.
第三方库有一个函数"ThirdPartyGrab"来启动一个连续的实时抓取,并获取一个指向一个函数的指针,该函数将在每次新帧到达时被调用.所以在普通的C应用程序中它是这样的:
ThirdPartyGrab (HookFunction);
Run Code Online (Sandbox Code Playgroud)
"HookFunction"需要声明为:
long _stdcall HookFunction (long, long, void*);
Run Code Online (Sandbox Code Playgroud)
或"BUF_HOOK_FUNCTION_PTR",声明为
typedef long (_stdcall *HOOK_FUNCTION_PTR) (long, long, void*);
Run Code Online (Sandbox Code Playgroud)
现在我有一个C++应用程序和一个类"MyFrameGrabber",它应该封装我所做的一切.所以我将钩子函数作为私有成员放入这样的:
long _stdcall HookFunction (long, long, void*);
Run Code Online (Sandbox Code Playgroud)
在我班上还有一个公共无效函数"StartGrab",应该启动Grab.在里面我试着打电话:
ThirdPartyGrab (..., HookFunction, ...);
Run Code Online (Sandbox Code Playgroud)
(毫不奇怪)失败了.它说对MyFrameGrabber :: HookFunction的函数调用错过了参数列表,我应该尝试使用&MyFrameGrabber :: HookFunction来创建指针.但是,传递"&MyFrameGrabber :: HookFunction"会导致另一个错误,即无法将其转换为BUF_HOOK_FUNCTION_PTR.
通过阅读C++ FAQ函数指针后,我认为我理解了这个问题,但无法解决问题.我试图使钩子函数静态,但这也导致转换错误.我还想过把钩子函数放在类之外,但我需要在钩子函数中使用类函数.还有其他方式还是我需要改变我的整个概念?
编辑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
Run Code Online (Sandbox Code Playgroud)
在我的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, ...);
}
Run Code Online (Sandbox Code Playgroud)
但这给了我一个错误,static MatroxFrameGrabber _instance;
因为找不到匹配的标准构造函数.这是正确的,因为我的MyFrameGrabber构造函数如下所示:
MyFrameGrabber (void* x,
const std::string &y, int z,
std::string &zz);
Run Code Online (Sandbox Code Playgroud)
我试图放入一个空构造函数,MyFrameGrabber();
但这会导致链接器错误.我应该将空参数传递给单例中的MyFrameGrabber构造函数吗?或者我需要一个单独的Hook类,如果是,我怎么能访问MyFrameGrabber函数?提前致谢.
第二次编辑15.01.08:我应用了这些更改,现在编译和链接.不幸的是我无法在运行时测试它,因为它是一个DLL,我还没有Debug Caller Exe,并且在初始化期间还有其他问题.我会将帖子标记为答案,因为我确信这是正确的方法.
您的私有成员方法有一个隐式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()
调用应该很容易具有功能齐全的签名,包括可用的参数名称时找到.
“&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...
}
};
Run Code Online (Sandbox Code Playgroud)
// 新定义: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);
}
Run Code Online (Sandbox Code Playgroud)
第二次编辑:您可以使用初始化方法稍微修改单例类,以使用适当的参数调用构造函数,但也许它并不比以下解决方案更优雅,后者更简单:
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, ...);
}
Run Code Online (Sandbox Code Playgroud)