2013-04-11 59 views
0

我遇到了函数指针的问题,并且我在网络上找到的任何东西都帮助我解决了这个问题。如何从成员函数中获取“简单”函数指针

我有选自C API,它需要一个void函数的指针的函数:

extern int APIFunction(int, void (*func)(int));

我有,我想,当我调用API函数把函数的类。

class MyClass 
{ 
    public: 
     void myFunction(int status, otherAPi arguments...); 
}; 

然后,我创建了一个指向我的会员功能,创建了类的新实例

typedef void (MyClass::*MyClassFunctionPointer)(int stat, otherAPi arguments...); 
MyClassFunctionPointer fctPointer= &MyClass::myFunction; 
LicenseSecurity instance; 

我得到一个错误,当我尝试打电话给我的API函数与我创建的函数指针:

E2034 Impossible to convert 'void (MyClass::*)(int, otherAPITypes...)' into 'void (*) (int, otherAPITypes...)' 
E2342 Bad type correspondence in the parameter 'func' ('void (*)(int, otherAPITypes...)' desired, 'void(int, otherAPITypes...)' obtained) 

int stat = APIFunction(5, fctPointer); // -> error 1 
int stat = APIFunction(5, instance.*fctPointer); // -> error 2 

我在第一和第二种情况分别得到了错误

我无法访问API函数,因此我无法修改它。为了总结这个问题:如何获得一个“简单的”C函数指针来放入我的类的成员函数的函数参数?

谢谢

+0

我认为boost :: bind在这里很有帮助 – Constantin 2013-04-11 20:49:33

+0

@Constantin然后他会有一个包装成员函数调用的函子......但他仍然无法将它传递给API函数。 – 2013-04-11 20:55:01

+0

[C++类成员函数回调]可能的重复(http://stackoverflow.com/questions/8079453/c-class-member-function-callback) – 2013-04-11 20:55:16

回答

2

不幸的是,你不能。抱歉。

理想情况下,您的API将接受类似std::function的东西,这将允许您包装自由函数或成员函数。但是如果你不能修改API,那么你别无选择,只能提供一个免费的功能。

+0

其实,在某些情况下,您可以这样做。出于这个原因,GCC有一个称为PMI转换的特殊功能。但是这对于所有方法都不适用(认为是多重虚拟继承)并且当然不是标准的,甚至在编译器中也不可移植。 – 2013-04-11 20:51:40

+0

gcc可以编译C++吗?因为我从来没见过c中的成员函数... – Constantin 2013-04-11 20:52:59

+1

@Constantin:是的,g ++只是gcc的包装器,具有特定选项 – newacct 2013-04-12 09:05:18

0

由于该函数在调用时需要该指针,因此无法获得指向非静态成员函数的“简单”函数指针。如果你要创建一个像这样的函数指针,那么当函数被调用时,就不会有这个指针供它引用。

0

用这种古老的C API,你不幸没有办法做到这一点。

你需要做的是使一个静态或非成员函数接受回调,然后找出哪个对象的实例调用成员。有些C API允许将用户数据传递给回调函数,在这种情况下,您可以使用它来存储有问题的this指针。如果这不是一个选项,您可以使用全局或单例对象,并且只允许注册一个这样的回调。

+0

问题是,使用静态或非成员函数时,我无法使用我的属性我需要它。 – Pierre 2013-04-12 12:15:50

0

您可以将回调声明为独立函数或类的方法为静态。棘手的部分是在回调中访问类实例指针。

理想情况下,精心设计的API允许您为回调指定用户定义的值。这允许您轻松传入一个类实例并直接在回调中访问它。但是这听起来像你没有使用这样的API,所以你需要使用一种解决方法。

如果您一次只有1个类实例与API一起使用,则可以将实例指针存储到全局变量中,并让回调使用全局变量来访问该实例。

但是,如果你有在同一时间使用了多类实例,你正在寻找一个解决方案置信转换,类似VCL的MakeObjectInstance()功能,它允许TWndMethod -signatured类的方法被用作Win32的窗口过程的回调。本质上,一块可执行的内存是动态分配的,存根汇编代码被写入块中,而实例指针和类方法指针也被存储在块中。然后将该块作为函数指针传递给API。当API调用“函数”时,存根代码被执行,必须操纵调用堆栈和CPU寄存器来调用存储的类方法指针,将存储的实例指针作为其隐藏参数this,同时保留其他参数的语义,调用堆栈,函数结果等等。

C++中没有任何东西真正实现了这种thunking本地。手动实现并不困难,但也不是微不足道的(查看VCL的Classes.pas源文件中的MakeObjectInstance()的源代码)。最难的部分是提出必要的存根代码,以匹配您特定类方法签名的语义。