天天看點

std::tr1::function std::tr1::bind

在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