在之前的一篇回調函數簡單例子中就寫了一個簡單的回調小例子,這裏補充一下。
一個對象的this指針並不是對象本身的一部分,不會影響sizeof(對象)的結果。this作用域是在類內部,當在類的非靜態成員函數中訪問類的非靜態成員的時候,編譯器會自動將對象本身的地址作爲一個隱含參數傳遞給函數。也就是說,即使你沒有寫上this指針,編譯器在編譯的時候也是加上this的,它作爲非靜態成員函數的隱含形參,對各成員的訪問均通過this進行。
爲了實現回調,我們必須把this指針給轉換掉!可爲了在該函數中可以直接操作該類中的成員,我們必須保留this指針!所以這是矛盾的。
在類封裝回調函數:
a.回調函數只能是全局的或是靜態的。
b.全局函數會破壞類的封裝性,故不予採用。
c.靜態函數只能訪問類的靜態成員,不能訪問類中非靜態成員
讓靜態函數訪問類的非靜態成員的方法:
在消息回調的函數參數中傳遞一個該類的指針即可,就像類中創建一個多線程的回調一樣.將類的指針傳遞給該回調函數,然後用該指針調用類的非靜態成員函數和指針.或者用一個類的全局指針數組,保存每一個創建出來的類的this指針,用全局指針去調用。如下:
class A()
回調函數中訪問非靜態成員
由於回調函數往往有固定定義,並不接受 A * pThis 參數
如:CALLBACK MyTimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime);
【解決方案1】:本方案當遇到有多個類實例對象時會有問題。原因是pThis指針只能指向一個對象。
class A()
{
static void a(); //靜態回調函數
void b(); //非靜態函數
static A * pThis; //靜態對象指針
}
A * A::pThis=NULL; //這句話必須要在cpp一開始就寫,不然編譯會報無法解析的外部符號的錯。
A::A() //構造函數中將this指針賦給pThis,使得回調函數能通過pThis指針訪問本對象
{
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;
A::A() //構造函數中將this指針賦給pThis,使得回調函數能通過pThis指針訪問本對象
{
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(); //回調函數中調用非靜態函數
};
}
原文連接:https://blog.csdn.net/u012072012/article/details/45537387