在c++的tr1中(technology
report)中包含一個function模闆類和bind模闆函數,使用它們可以實作類似函數指針的功能,但卻卻比函數指針更加靈活,特别是函數指向類
的非靜态成員函數時。可以參考scott meyers. <<effective c++ (3rd edition)>>. item
35.下面具體說明其使用方法。
一、指向全局函數或靜态成員函數時
因為在本質上講全局函數和靜态成員函數沒有區
别,使用方法上除了靜态成員函數在引用時要在前面加域作用符classname::外,沒有其它任何差別,事實上全局函數也有可能放入命名空間,或者使用
全局域作用符,例如 namespace::function()
或::function,這樣不僅本質上相同,形勢上也與靜态成員函數一緻了,是以它們是沒有差別的,放到一起讨論。
這種情況比較簡單,隻需要定義一個類型
#include <iostream>
#include <iomanip>
#include <tr1/memory>
#include <tr1/functional>
typedef std::tr1::function<void (int)>
handlerevent;
然後再定義一個成員變量
class sharp{
public:
handlerevent handlerevent;
};
然後在其它函數内就可以通過設定handlerevent的值來動态裝載事件響應函數了,如:
class rectangle{
private:
std::string name;
sharp sharp;
void initial(void);
const sharp getsharp() const;
static void onevent(int param){
//---------------(1)
std::cout << "invode onevent
method,get parameter: " << param << std::endl;
}
//類的實作方法
void rectangle::initial(){
sharp.handlerevent =
handlerevent(&rectangle::onevent); //---------------(2)
std::cout << "invode initial function!"
<< std::endl;
}
const sharp rectangle::getsharp() const{
return sharp;
//下面為測試函數:
int main(int argc,char *argv[]){
std::cout <<"hi: " << std::setw(50)
<< "hello world!" << std::endl;
rectangle rectangle;
rectangle.initial(); //---------------(3)
rectangle.getsharp().handlerevent(23);
//---------------(4)
//輸出結果如下:
hi:
hello
world!
invode initial function!
invode onevent method,get parameter: 23
//---------------(5)
注 意,這裡使用了靜态成員函數,如果把rectangle前面的static去掉這段代碼不能工作,編譯都不能通過,因為靜态成員函數與非靜态成員函數的參
數表不一樣,原型相同的非靜态函數比靜态成員函數多一個參數,即第一個參數this指針,指向所屬的對象,任何非靜态成員函數的第一個參數都是this指
針,是以如果把rectangle前面的static去掉,其函數原型等效于下面的一個全局函數:
void onevent(rectangle* this, int);
所 以,這與handlerevent所聲明的函數類型不比對,編譯将不能通過。而且,既然靜态成員函數沒有this指針,是以上面(3)處的調用使
sharp對象中的handlerevent使向了rectangle的靜态方法onevent(),這樣當通過(4)處這樣調用時就會自動執行(1)處
的靜态函數onevent()。
二、std::tr1::bind()模闆函數的使用
通過上面的std::tr1::function
可以對靜态成員函數進行綁定,但如果要對非靜态成員函數的綁定,需用到下面将要介紹的bind()模闆函數.
首先說bind的用法,其聲明如下所示:
bind(function fn, t1 t1, t2 t2, …, tn
tn);
其中fn為将被調用的函數,t1…tn為函數的參數。如果不指明參數,則可以使用占位符表示形參,點位符格式為
std::tr1::placehoders::_1, std::tr1::placehoders::_2,
…, std::tr1::placehoders::_n
将上例中rectangle::onevent(int
param)前的static去掉改為非靜态成員函數,則進行動态綁定使得程式正常運作,将rectangle::initial(void)的定義修改為:
std::tr1::bind(&rectangle::onevent,this,std::tr1::placeholders::_1/*因onevent函數需要一個參數,是以用一占位符*/);
這樣,便動态裝載函數成功。其它測試資料都不用進行修改。測試結果于上一樣。
三、指向虛成員函數的使用
對于虛成員函數的情況與上面第2節所說相同,仍然可以實作慮函數的效果。如果定義類square繼承自rectangle,将
rectangle::onevent重載,定義一個新的square::onevent,rectangle::initialize中的函數不變,仍然使用rectangle::onevent進進綁定,則調用成員object.onevent()時,具體執行rectangle::onevent還
是square::onevent,看object所屬對象的靜态類型是rectangle還是square而定.
下面為簡單示例:
我們首先修改一個上面rectangle的initial()方法,改為虛函數。如:
virtual void onevent(int param){
std::cout <<
"invode rectangle‘s onevent method,get parameter: "
<< param << std::endl;
然後我們再寫一個square類來繼承rectangle類。并重寫onevent方法。如:
class square : public rectangle{
void onevent(int param){
"invode square‘s onevent method,get parameter: " <<
param << std::endl;
測試代碼:
rectangle.initial();
rectangle.getsharp().handlerevent(23);
square square;
square.initial();
square.getsharp().handlerevent(33);
運作後的結果如下:
hi:
hello world!
invode rectangle‘s onevent method,get parameter: 23
invode square‘s onevent method,get parameter: 33
這樣我們就可以看到sharp會針對具體對象來調用相應的onevent()方法。 上面的程式示例讀者可自行研習。
【轉載】http://blog.csdn.net/xiucaijiang/article/details/5999441