C++中std::tr1::function和bind 组件的使用
在C++的TR1中(Technology Report)中包含一個function模板類和bind模板函數,使用它們可以實現類似函數指針的功能,但卻卻比函數指針更加靈活,特別是函數指向類的非靜態成員函數時??梢詤⒖糞cott 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;
public:
?? ?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)的定義修改為:
void Rectangle::initial(){
?? ?sharp.handlerEvent = std::tr1::bind(&Rectangle::onEvent,this,std::tr1::placeholders::_1/*因onEvent函數需要一個參數,所以用一占位符*/);
?? ?std::cout << "invode initial function!" << std::endl;
}
這樣,便動態裝載函數成功。其它測試數據都不用進行修改。測試結果于上一樣。
三、指向虛成員函數的使用
對于虛成員函數的情況與上面第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{
public:
void onEvent(int param){
?? ? ? ?std::cout << "invode Square's onEvent method,get parameter: " << param << std::endl;
?? ?}
};
測試代碼:
int main(int argc,char *argv[]){
?? ?Rectangle rectangle;
?? ?rectangle.initial();
?? ?rectangle.getSharp().handlerEvent(23);
?? ?Square square;
?? ?square.initial();
?? ?square.getSharp().handlerEvent(33);
}
運行后的結果如下:
hi: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? hello world!
invode initial function!
invode Rectangle's onEvent method,get parameter: 23
invode initial function!
invode Square's onEvent method,get parameter: 33
這樣我們就可以看到sharp會針對具體對象來調用相應的onEvent()方法。 上面的程序示例讀者可自行研習。
總結
以上是生活随笔為你收集整理的C++中std::tr1::function和bind 组件的使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vector利用swap()函数进行内存
- 下一篇: wince6下usb摄像头(UVC)使用