如何實現類的成員函數作為回調函數


 
        

許多程序員都發現,利用MFC或者其它的C++應用編寫回調函數是非常麻煩的,其根本原因是回調函數是基於C編程的Windows SDK的技術,不是針對C++的,程序員可以將一個C函數直接作為回調函數,但是如果試圖直接使用C++的成員函數作為回調函數將發生錯誤,甚至編譯就不能通過。通過查詢資料發現,其錯誤是普通的C++成員函數都隱含了一個傳遞函數作為參數,亦即“this”指針,C++通過傳遞一個指向自身的指針給其成員函數從而實現程序函數可以訪問C++的數據成員。這也可以理解為什么C++類的多個實例可以共享成員函數但是確有不同的數據成員。由於this指針的作用,使得將一個CALLBACK型的成員函數作為回調函數安裝時就會因為隱含的this指針使得函數參數個數不匹配,從而導致回調函數安裝失敗。要解決這一問題的關鍵就是不讓this指針起作用,通過采用以下兩種典型技術可以解決在C++中使用回調函數所遇到的問題。這種方法具有通用性,適合於任何C++。
1). 不使用成員函數,直接使用普通C函數,為了實現在C函數中可以訪問類的成員變量,可以使用友元操作符(friend),在C++中將該C函數說明為類的友元即可。這種處理機制與普通的C編程中使用回調函數一樣。
2). 使用靜態成員函數,靜態成員函數不使用this指針作為隱含參數,這樣就可以作為回調函數了。靜態成員函數具有兩大特點:其一,可以在沒有類實例的情況下使用;其二,只能訪問靜態成員變量和靜態成員函數,不能訪問非靜態成員變量和非靜態成員函數。由於在C++中使用類成員函數作為回調函數的目的就是為了訪問所有的成員變量和成員函數,如果作不到這一點將不具有實際意義。解決的辦法也很簡單,就是使用一個靜態類指針作為類成員,通過在類創建時初始化該靜態指針,如pThis=this,然后在回調函數中通過該靜態指針就可以訪問所有成員變量和成員函數了。這種處理辦法適用於只有一個類實例的情況,因為多個類實例將共享靜態類成員和靜態成員函數,這就導致靜態指針指向最后創建的類實例。

http://blog.csdn.net/u013394556/article/details/43056397

 

1.回調函數的說明:

在進行軟件開發的過程中,常會用到一些聲明為CALLBACK的函數,這些函數就是回調函數。使用回調函數可以改善軟件的結構、提高軟件的復用性。比如,在一個規模較大的軟件項目中,可以將一些資或相對獨立的處理模塊封裝到動態連接庫(DLL) 中,然后通過回調函數在不同的場合來使用這些資源和模塊。利用回調函數還可以進行程序間復雜的通信,實現一些通知的功能,在某些場合它是比消息更合適的一種方式;在一些特殊的情況下,回調函數更有不可替代的作用。Win32 API 中有許多回調函數的應用,在進行軟件設計時也會經常用到這種函數,而有些時候則需要編寫自己的回調函數。因此,理解回調函數的原理並掌握它的基本用法是非常必要的。

C ++ 是當代使用最廣泛的語言,從嵌入式系統到大型機系統、從Linux到Windows,在大型系統的編制中,到處都是它的身影。它以高效和易編程性獲得了許多資深程序員的信賴。在DirectX Play 開發過程中,經常需要使用到回調函數,直接使用回調函數顯得復雜麻煩,采用用C + + 實現對回調函數的封裝, 使回調函數變得方便實用,對於DirectX Play 等編程就顯得是非常有意義的。 
回調函數簡單講就是一個函數指針。寫一個函數,然后把函數地址傳遞給這個函數指針就可以了。

回調函數的原形對C ++ 的成員函數用做回調函數的影響是什么? 
編寫回調函數簡單地說就是函數原形一致。函數的輸入參數,輸出參數一致是很容易保證的。要注意調用類型一致性。函數傳參數有好幾種類型,搞錯了傳參數的方式,系統必然運行錯誤。一般來說都是WINAPI 傳參數方式。要注意C ++ 的類的成員函數和一般的C 函數的區別。C + + 類采用this 規則傳遞函數。在使用類的成員函數作為回調函數,要求該成員函數被聲名為靜態成員函數,並且注意函數聲名的時候要同時聲明好參數傳遞規則。 
  
2.我的回調函數的理解, 
  
模塊A ,模塊B,如果模塊B 中調用模塊A 的東西, 在模塊A中發生一個事件或操作,調用B的函數處理,這就才用了回調函數的機制。

C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm

讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm

讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm

讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm

C++11 獲取系統時間庫函數 time since epoch http://www.linuxidc.com/Linux/2014-03/97446.htm

C++11中正則表達式測試 http://www.linuxidc.com/Linux/2012-08/69086.htm

3.例子的實現

模塊A的代碼 
#ifndef __A_H 
#define __A_H

class A 

public: 
A(void){} 
public: 
~A(void){}


typedef void (*perfect)(int );  //聲明回調函數


public: 
void CallBackFunc(void (*perfect)(int ),int n)  //給模塊B調用的函數 

  perfect(n);  //調用的函數 
}

 


}; 
#endif  //__A_H

模塊B的代碼

#include <iostream> 
#include "A.h" 
using namespace  std;

void perfect(int n)  //這個函數要求是全局的,或者是類中的靜態成員變量 

cout<<n<<endl; 
}


int main() 

A a; 
a.CallBackFunc(perfect,100);    //調用模塊A的代碼。


return 0;


}

靜態成員函數調用非靜態成員函數  應用於回調函數

代碼如下 
模塊A的代碼 
#ifndef __CALLBACKTEST_H 
#define __CALLBACKTEST_H


class CallBackTest 

public: 
CallBackTest(void); 
public: 
~CallBackTest(void); 
typedef void (*perfect)(void*,int );  //聲明回調函數 
public: 
  void CallBackFunc(void* pThisOBject,void (*perfect)(void*,int ),int n) 

p=perfect; 
m_n=n; 
m_pThisObject=pThisOBject; 
}


  void ExecBackFunc() 
  { 
p(m_pThisObject,m_n); 
  }


private:  
perfect  p; 
int m_n; 
void* m_pThisObject; 
};


#endif //__CALLBACKTEST_H

模塊B的代碼

#include <iostream> 
#include "CallBackTest.h" 
using namespace std;


class testMai 

public: 
static void perfect(void *pdata,int n) 

testMai* pObject=(testMai*)pdata; 
pObject->test(n);


}


void Exec() 

CallBackTest callbackTest; 
callbackTest.CallBackFunc(&this,perfect,100);


cout<<"ni hao"<<endl;


callbackTest.ExecBackFunc();


}


void test(int n) 

int i=1; 
int count=0; 
m=9; 
for(i=1;i<n;i++) 
{


if(0==n%i) 

count+=i; 


if(count==n) 
//printf("%d是完數\n",n); 
{


cout<<n<<"是完數"<<endl; 

else  

cout<<n<<"bu shi de "<<endl; 

}


private: 
int m;


};

 


int main() 

testMai testMai; 
testMai.Exec(); 
return 0; 
}

本文永久更新鏈接地址http://www.linuxidc.com/Linux/2014-06/102932.htm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM