2015-11-18 3 views
1

Я пытаюсь использовать метод класса в качестве функции обратного вызова в другом классе в Qt. Это то, что я хочу сделать:Как использовать метод класса C++ в качестве функции обратного вызова

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)); 
    } 
} 

Вышеприведенный код не компилируется. Он выдает следующее сообщение об ошибке:

cannot convert 'A::callBackFunc' from type 'void (A::)()' to type 'void (*)()

Как я могу позвонить callBackFunc в Func() метод класса С в otherFunc()?

+0

Объявление, если отсутствует 'otherFunc'. –

+0

'otherFunc' - это API, предоставляемый внешней библиотекой. Я включил его заголовочный файл в файл cpp. – Luffy

+0

Существуют ли какие-либо другие перегрузки функции 'otherFunc'? Например, тот, который принимает 'std :: function' или типы шаблонов? Если это так, вы можете использовать 'std :: bind'. –

ответ

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; 
} 
0

Как уже говорилось ранее, метод класса требует этого ptr. Один из способов сделать это - захватить «это» с помощью lambda C++ 11. Вот один пример:

Callback with lambda capturing 'this' ptr

0

Прежде всего, вы не можете пройти C++ элемент стиля указатель функции в с функцией стиль указатель на прямо, но косвенно, есть два способа достижения Цель.

  • статический метод член
    C++ адрес функции-члена основан на экземпляре, это

this + offset

поэтому каждый метод член должен имеет этот указатель, компилятор сделал это ,

Class B: public A { 
public: 
    B(); 
    ~B(); 

    void callBackFunc() { 
     emit signal1(); 
    } 
} 
B b; 
b.callBackFunc(); 

это сумма

callBackFunc(&b) 

, поэтому компилятор возникает ошибка.
Статический метод-член не нуждается в указателе «this», поэтому вы можете передать его в функцию стиля c, точно так же, как @ jpo38.

  • санк

что стуком? вы можете найти его в источнике WTL. Вывод: вы можете использовать этот «указатель» этого пакета.Вот случай (reference page)

//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; 
}