愛悠閑 > 函數對象(functor)簡介

函數對象(functor)簡介

分類: 【3】STL  |  作者: weiwenhp 相關  |  發布日期 : 2014-08-23  |  熱度 : 625°

函數對象又叫偽函數.函數對象本來是一個類,但由于基本上沒干啥事,就只封裝一個函數在里面,并且被封裝的函數還是通過重載運算符()來實現.

可能你很是納悶,為啥搞個這東東出來啊?

其實是這樣的,剛開始一些簡單應用完全用個函數完全可以搞定,傳個函數指針就行了.但這樣不夠靈活,可擴展性不好.于是干脆整個類出來得了.

 

函數指針的缺陷

還是舉個例子來瞧瞧吧~

如果我們有個工廠要招人,然后要符合很多標準才行.本著分工合作的原則,那個判斷符合條件的工作完全由另一個函數來完成.(當然這只是為了舉例方便,有點牽強的)

假如函數IsOK(int userID)來判斷符合條件不.

bool IsOK(int userID)

{

    //假如通過userID在數據庫查找各種信息,然后判斷

   int age = GetAge(userID);  //這個函數的實現就省略了,其他很多判斷信息也不管了

   if( age > 18)

       return true;

    else

      return false;

}

void PrintAllLaborName(int userID, string name , bool (*pFun)(int))   //第二個參數是個函數指針

{

    if( pFun(userID) )  //符合條件則打印姓名

         cout<<name<<endl;

}

 

如果是簡單的應用,就像上面一樣在PrintAllLaborName中傳個函數指針就行了,但啥時突然要變成需要其他一些條件,函數的參數要變.這樣改起來就不太方便.

假如IsOK(int )要變成 IsOk(int , string) ,這樣就得有兩處要改了.一個是IsOK函數本身,另一個就是PrintAllLaborName的參數.

那我們知道面向對象類的好處就是封裝,對外提供接口就行了.要改只改類里面的,接口不變.于是我們就想著把函數IsOK封裝到一個類里面去.

 

函數對象

template<class T>

struct CheckCondition  //這就是一個函數對象,只要重載運算符()

{

   bool operator() (int userID , T otherInfo)  //假如有很多信息要傳,到時定義一個類然后用T傳過來就行的

   {

        // if( Check( userID , otherInfo) )  這里就不實現該功能了

            return true;

         //else

           //return false;

     }

}

 

template<class T>

void PrintAllLaborName(int userID, string name , T fun) //第二個參數是個函數對象

{

if( fun(userID, name ) //符合條件則打印姓名

cout<<name<<endl;

}

 

測試代碼

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() );

 

函數對象傳函數時的迷惑

看完例子你可能有兩個疑問,

一個是重載運算符()的好處,

另一個是函數對象用起來有點怪怪的.都沒有看到那個類在哪里實例化

 

重載()的好處是它的參數不受限制的,所以你可以模仿任意函數.而像其他運算符(一元運算符,二元運算符)只能有一個或兩個參數.

 

函數對象的實例化:

首先是函數的形參是個類,然后里面調用,這好理解

template<class T>

void PrintAllLaborName(int userID, string name , T fun)

然后里面調用fun(userID, name )

 

但這里就不明白了

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() );

CheckCondition<string>()這個參數也太怪了吧.

如果是CheckCondition<string> checkCon;

然后PrintAllLaborName ( 123, "arwen" , checkCon);這樣就非常好理解了.

實例化成一個對象,然后傳過去就好了嘛.實際上這樣是完全可以的,一點也沒錯.

 

不過大多數時候我們卻沒這樣用,而是CheckCondition<string>()這樣用,為啥? 因為這樣有這么個好處.

我們知道CheckCondition<string> checkCon;這樣實例化一個對象后,等你調用完了函數PrintAllLaborName該對象仍然沒出作用域,沒有被析構掉.

而CheckCondition<string>()就是調用構造函數,這樣是傳一個臨時對象過去,一調用完函數就被析構(調用完立馬被析構,這就是好處)

 

PrintAllLaborName ( 123, "arwen" , CheckCondition<string>() )這樣傳個參數過去,發生的動作是

void PrintAllLaborName(int userID, string name , T fun)

{

//下面兩步操作是后臺實現的

CheckCondition<string> tmp ;

fun = tmp;

}



快乐彩中奖说明