回調函數中調用類中的非靜態成員變量或非靜態成員函數
【問題】如何在類中封裝回調函數?
a.回調函數只能是全局的或是靜態的;
b.全局函數會破壞類的封裝性,故不予采用;
c.靜態函數只能訪問類的靜態成員,不能訪問類中非靜態成員。
1. 如何讓靜態函數訪問類的非靜態成員。
a.聲明一靜態函數a(),將類實例對象指針做為參數傳入。如:
class A() { static void a(A *); //靜態函數 void b(); //非靜態函數 } void A::a(A * pThis) { pThis->b(); //靜態函數中調用非靜態函數 }
b.回調函數中訪問非靜態成員
由於回調函數往往有固定定義,並不接受 A * pThis 參數
如:CALLBACK MyTimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
【解決方案1】:本方案當遇到有多個類實例對象時會有問題。原因是pThis指針只能指向一個對象。
class A() { static void a(); //靜態回調函數 void b(); //非靜態函數 static A * pThis; //靜態對象指針 } // 構造函數中將this指針賦給pThis,使得回調函數能通過pThis指針訪問本對象 A * A::pThis=NULL; A::A() { pThis = this; } void A::a() { if ( pThis == NULL ) return; pThis->b(); //回調函數中調用非靜態函數 }
【解決方案2】:本方案解決多個類實例對象時方案1的問題。用映射表存所有對象地址,每個對象保存自己的ID號。
typedef CMap<UINT, UINT, A*, A*> CAMap; class A() { static void a(); //靜態回調函數 void b(); //非靜態函數 int m_ID; //本對象在列表中的ID號 static int m_SID; //靜態當前對象ID.(需要時,將m_ID賦值給m_SID以起到調用本對象函數的功能) static CAMap m_Map; //靜態對象映射表 } CAMap A::m_Map; int A::m_SID=0; // 構造函數中將this指針賦給pThis,使得回調函數能通過pThis指針訪問本對象 A::A() { if(m_Map.IsEmpty()) { m_ID=1; } else { m_ID=m_Map.GetCount()+1; } m_Map.SetAt( m_ID, this ); } void A::a() { if (m_Map.IsEmpty()) return; A * pThis=NULL; if( m_Map.Lookup(m_SID,pThis) ) { pThis->b(); // 回調函數中調用非靜態函數 }; }
【參考資料 感謝作者】
1、回調函數中調用類中的非靜態成員變量或非靜態成員函數