我正在尝试使用类的方法作为Qt中另一个类的回调函数。这就是我想要做的事情:
Class A: public QObject
Q_OBJECT
public:
virtual void callBackFunc() = 0;
}
Class B: public A {
public:
B();
~B();
void callBackFunc() {
emit signal1();
}
}
Class C : public QObject {
Q_OBJECT
private:
A* m_b;
public:
C() {
m_b = new B();
}
~C();
void func() {
otherFunc(1,2,m_b->callBackFunc); // An API provided by an external library: otherFunc(int,int,void (*function)(void));
}
}
上面的代码没有编译。它会引发以下错误:
无法转换' A :: callBackFunc'来自类型' void(A ::)()'键入' void (*)()
如何在otherFunc()中的C类func()方法中调用callBackFunc?
答案 0 :(得分:3)
如果您的API使用void (*function)(void)
,则无法将其传递给void (*A::function)(void)
。
第一个是函数,第二个是类方法(需要使用一个对象)。这里只能使用静态类方法(类似函数)。
或者,您可以使用全局静态变量来标识必须调用callBackFunc
的对象。 但要非常小心(C::func
不能递归调用或来自不同的线程......)。
static B* objectToCallFuncOn = NULL;
void globalFunc()
{
assert( objectToCallFuncOn );
objectToCallFuncOn->callBackFunc();
}
void C::func()
{
objectToCallFuncOn = m_b;
otherFunc(1,2,&globalFunc);
objectToCallFuncOn = NULL;
}
答案 1 :(得分:0)
正如之前的回答所说,类方法需要这个ptr。一种方法是使用C ++ 11 lambda捕获'this'。这是一个例子:
答案 2 :(得分:0)
首先,你不能直接将 c ++样式成员函数指针传递给 c样式函数指针,但间接地,有两种方法可以实现一个目标。
此+偏移
所以每个成员方法都必须有这个指针,编译器就这样做了。
Class B: public A {
public:
B();
~B();
void callBackFunc() {
emit signal1();
}
}
B b;
b.callBackFunc();
它等于
callBackFunc(&b)
这就是您的编译器发生错误的原因 静态成员方法并不需要"这个"指针,所以你可以将它传递给c风格函数,就像@jpo38所说的那样。
//main.cpp
#include <iostream>
#include <Windows.h>
#include <process.h>
#include "Thunk.h"
#include "resource.h"
using namespace std;
/////////////////////////////////////////////////////////
//第一个:__cdecl 回调类型
/////////////////////////////////////////////////////////
typedef int (__cdecl* CB)(int n);
void output(CB cb)
{
for(int i=0; i<3; i++){
cb(i);
}
}
class ACDCEL
{
public:
ACDCEL()
{
void* pthunk = m_Thunk.Cdeclcall(this,&ACDCEL::callback);
::output(CB(pthunk));
}
private:
int __cdecl callback(int n)
{
cout<<"n:"<<n<<endl;
return n;
}
private:
AThunk m_Thunk;
};
/////////////////////////////////////////////////////////
//第二个:__stdcall 回调类型:封装窗口类
/////////////////////////////////////////////////////////
class ASTDCALL
{
public:
ASTDCALL()
{
void* pthunk = m_Thunk.Stdcall(this,&ASTDCALL::DialogProc);
DialogBoxParam(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIALOG1),NULL,(DLGPROC)pthunk,0);
}
private:
INT_PTR CALLBACK DialogProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
case WM_CLOSE:
EndDialog(hWnd,0);
return 0;
}
return 0;
}
private:
AThunk m_Thunk;
};
/////////////////////////////////////////////////////////
//第三个:__stdcall 回调类型:内部线程
/////////////////////////////////////////////////////////
class AThread
{
public:
AThread()
{
void* pthunk = m_Thunk.Stdcall(this,&AThread::ThreadProc);
HANDLE handle = (HANDLE)_beginthreadex(NULL,0,(unsigned int (__stdcall*)(void*))pthunk,(void*)5,0,NULL);
WaitForSingleObject(handle,INFINITE);
CloseHandle(handle);
}
private:
unsigned int __stdcall ThreadProc(void* pv)
{
int i = (int)pv;
while(i--){
cout<<"i="<<i<<endl;
}
return 0;
}
private:
AThunk m_Thunk;
};
int main(void)
{
ASTDCALL as;
ACDCEL ac;
cout<<endl;
AThread at;
return 0;
}