std::tr1::function
在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;
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:
virtual 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);
}
執行後的結果如下:
invode initial function!
invode Rectangle's onEvent method,get parameter: 23
invode initial function!
invode Square's onEvent method,get parameter: 33
這樣我們就可以看到sharp會針對具體物件來呼叫相應的onEvent()方法。 上面的程式示例讀者可自行研習。
相關文章
- std::function用法學習Function
- C++11 std::bind std::function 高階用法C++Function
- c++中關於智慧指標std::tr1::shared_ptr的用法C++指標
- c++11:std::boolalpha、std::noboolalphaC++
- std::vector 和 std::list 區別
- std::reserve和std::resize的區別
- 設計模式(四)std::function介面程式設計徹底取代抽象工廠和工廠方法設計模式Function程式設計抽象
- `std::packaged_task`、`std::thread` 和 `std::async` 的區別與聯絡Packagethread
- 詭異!std::bind in std::bind 編譯失敗編譯
- javascript 中function(){},new function(),new Function(),Function 摘錄JavaScriptFunction
- 【C++併發實戰】(三) std::future和std::promiseC++Promise
- C++ 標準庫 std::set std::multiset swap()的使用C++
- ODRDMS_GOV_STDGo
- std::count 函式函式
- C++(std::vector)C++
- (C++11/14/17學習筆記):std::atomic續、std::async與std::thread對比C++筆記thread
- c++11:std::bindC++
- std::map initializer list syntax ?
- std::remove_if 介紹REM
- (不要)使用std::threadthread
- std::make_shared
- 透徹理解C++11新特性:右值引用、std::move、std::forwardC++Forward
- 智慧指標思想實踐(std::unique_ptr, std::shared_ptr)指標
- $(function(){})與(function($){....})(jQuery)的區別FunctionjQuery
- 【54】讓自己熟悉包括TR1在內的標準程式庫
- c++ std::vector 切記C++
- c++11:std::is_sameC++
- 理解 std::declval 和 decltype
- std::async的使用總結
- JavaScript FunctionJavaScriptFunction
- javascript Function()JavaScriptFunction
- sendDataByUdp FunctionUDPFunction
- Substr FunctionFunction
- Function : dumpFunction
- [Bash] functionFunction
- C++ 智慧指標詳解: std::unique_ptr 和 std::shared_ptrC++指標
- std::numeric_limits::max() std::numeric_limits::min()編譯錯誤MIT編譯
- std::string的工具函式函式