Reference : http://johnniebooks.blogspot.tw/2010/12/c-classcallback-function.html
在C++ 的類別中如何使用API的callback function, 相信這是剛學會callback function程式員會遇到的問題, 所以在這整理一下解決的方法.
1.若callback function要成為類別的member function必須宣告成static
解析 - 首先, 我們先來釐清類別中的成員函式, 是如何存取成員變數(注意: 記憶體中只會有一份類別成員函式, 而類別成員變數可能有好幾份).
關鍵就是透過this指標. 因為, C++在編譯時, 會隱含this指標在類別的成員函式中
例如有一個類別和其成員函式為:
class CShape
{
...
public:
void SetColor(int color) { m_color = color;};
}
經過編譯後, 會變成
class CShape
{
...
public:
void SetColor(int color, (CShape*)this) { this->m_color = color; }
};
因此, 透過this指標可用來指向呼叫它的物件(instance), 進而存取各自的成員變數.
而callback function通常是由系統呼叫, 也就是系統不需經由任何物件呼叫此函式, 因此member callback function的this 指標會沒有指向任何實體物件, 這將會造成錯誤.
為了不要讓callback function自動含有this指標, 可以將callback function宣告成static member function.
如此一來, callback function就變成 global function, 不需透過物件的實體就可呼叫.
2.若要在callback function中存取類別成員變數或成員函式, 需要修改callback function prototype, 讓函式的參數列中, 可傳入this指標.
解析 - 由於static member function是屬於類別而不是物件, 所以呼叫static member function時, 不會傳入物件的位址, 所以static member function中不會有this指標, 因此, static member function中不允許使用non-static成員.
所以, 如果要在static callback function中存取non-static成員, 需要在callback functuon的參數列表中傳入物件的this指標.
例如API中有一個callback function宣告如下:
void (*TouchCallback)(TouchPoint p);
若要成為類別的成員函式, 可改為:
void (*TouchCallback)(TouchPoint p, void* pInstance);
下面為範例:
有一個Touch API, 它利用callback的方法來取得觸控點資料.其介面如下:
#ifdef TOUCHAPI_EXPORTS
#define TOUCH_API __declspec(dllexport)
#else
#define TOUCH_API __declspec(dllimport)
#endif
// 定義觸控點的相關資訊
struct TouchPoint
{
int X;
int Y;
};
// 定義可傳入this指標的callback function prototype
typedef void (_stdcall *CB_TOUCH_CLASS_FUNC) (TouchPoint, void* pObject);
// 定義了一個RegisterCBTouchMemberFunc的函式,
// 可傳入一個具有CB_TOUCH_FUNC型別的callback function
TOUCH_API void RegisterCBTouchMemberFunc(CB_TOUCH_CLASS_FUNC callback,void* pObject);
定義一個CTouchClass的類別, 必且利用Touch API的callback function 作為member function, 程式碼如下:
TouchClass.h
#include "TouchAPI.h"
class CTouchClass
{
private:
int m_x;
int m_y;
public:
CTouchClass(void);
~CTouchClass(void);
public:
static void _stdcall TouchCallback(TouchPoint point, void* pObject);
public:
int GetTouchX();
int GetTouchY();
};
TouchClass.cpp
#include "StdAfx.h"
#include "TouchClass.h"
CTouchClass::CTouchClass(void)
{
this->m_x = 0;
this->m_y = 0;
}
CTouchClass::~CTouchClass(void)
{
this->m_x = 0;
this->m_y = 0;
}
// 利用this指標存取member function
void CTouchClass::TouchCallback(TouchPoint point, void* pObject)
{
CTouchClass* pClass = (CTouchClass*)pObject;
pClass->m_x = point.X;
pClass->m_y = point.Y;
}
int CTouchClass::GetTouchX()
{
return m_x;
}
int CTouchClass::GetTouchY()
{
return m_y;
}
請先 登入 以發表留言。