在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, 不需透過物件的實體就可呼叫.
如此一來, 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; }
沒有留言:
張貼留言