日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

仿函数(函数对象)

發布時間:2023/11/30 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 仿函数(函数对象) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載:http://www.cnblogs.com/wuchanming/p/4411867.html

本文乃作者學習《C++標準程序庫》的學習筆記,首先介紹了仿函數(函數對象)和函數適配器(配接器)的概念,然后列出STL中所有的仿函數,以及函數適配器,并摘錄了幾個例子演示仿函數和函數適配器的用法,最后討論了仿函數的組合,以及實現方法。

1.仿函數是什么東西?

《C++標準程序庫》里對仿函數的解釋是:仿函數是泛型編程強大威力和純粹抽象概念的又一例證。你可以說,任何東西,只要其行為像函數,它就是一個函數。因此如果你定義了一個對象,行為像函數,它就可以被當做函數來用。

那么,什么才算具備函數行為呢?所謂函數行為,是指可以"使用小括號傳遞參數,籍以調用某個東西"。例如:

function(argc1, argc2);

如果你指望對象也可以如此這般,就必須讓它們也可以被"調用"——通過小括號的運用和參數的傳遞。你只需要定義operator(),并給予合適的參數型別:

class X {public: // define 'function call' operator return-value operator()(arguments) const; ...... };

現在,你可以把這個類別的對象當做函數來調用了:

X fo; ...... // call operator () for function object to fo(argc1, argc2);

上述調用等價于:

fo.operator() (argc1, argc2);

總結如下:

  • 函數對象是一個普通對象
  • 重載了operator ()操作符
  • 函數對象一般都比較簡單,主要用到operator()操作,其他成員函數和成員變量都是為operator()服務

為了幫助理解仿函數,我們來看一個例子:

#include <algorithm> class gen_by_two { public: gen_by_two( int seed = 0 ) : _seed( seed ){} int operator()() { return _seed += 2; } private: int _seed; }; vector<int> ivec( 10 ); // fills ivec: 102 104 106 108 110 112 114 116 118 120 generate_n( ivec.begin(), ivec.size(), gen_by_two(100) );
或者

generate_n( ivec.begin(), ivec.size(), gen_by_two() );

上面的程序使用generate_n函數,給容器賦值,在調用gen_by_two(100)的時候,我們其實是生成了一個對象,并調用對象的構造函數給成員變量賦值,然后多次(v.size())調用該變量的operator()成員函數,將返回的值依次存入容器中。

2.函數適配器又是什么東西?

函數適配器又稱"函數配接器",是只能夠將仿函數和另一個仿函數(或某個值,或某一個函數)結合起來的仿函數。函數適配器聲明于<functional>中。

下面來看一個例子:

find_if(coll.begin(), coll.end(), //range bind2nd(greater<int>(), 42));criterion

其中表達式bind2nd(greater<int>(),42)導致一個組合型的仿函,檢查某個int值是否大于42.實際上bind2nd是將一個二元仿函數轉換為一個一元仿函數。bind2nd的意思就是將42作為比較(greater<int>())函數的第二個參數,也就相當于是elem.value > 42,如果容器中沒有42這個值,那么下面這條語句和上面的語句是一樣的。

find_if(coll.begin(), coll.end(), //range bind1st(less<int>(), 42));criterion

上面兩個小例子演示了適配器的功能,同時還講解了bind1st和bind2nd的區別。

3.預定義的仿函數

4.預定義的函數適配器

5.仿函數(以及函數適配器)的使用示例

下面摘錄幾個《C++標準程序庫》上的例子,以及個別我自己補充的實例,用于演示仿函數的使用,希望能夠通過例子快速掌握仿函數。

5.1 查找25或者35第一次出現的位置

pos = find_if(coll.begin(), coll.end(), //range compose_f_gx_hx(logical_or<bool>(), //criterion bind2nd(equal_to<int>(), 25), bind2nd(equal_to<int>(), 35)));

5.2 將集合中全部元素都設為相反值

transform(coll.begin(), coll.end(),//source coll.begin(),//destination negate<int>());//operation

5.3 對集合中的所有元素求平方

transform(coll.begin(), coll.end(),//first source coll.begin(),//second source coll.begin(),//destination multiplies<int>());//operation

5.4 所有元素乘以10

transform(coll.begin(), coll.end(),//source back_inserter(coll2),//destination bind2nd(multiplies<int>(),10));//operation

5.5 將a替換為b

replace_if(coll2.begin(), coll2.end(),//range bind2nd(equal_to<int>(), 70),//replace criterion 42);//new value

5.6 刪除小于50的元素

coll.erase(remove_if(coll.begin(), coll.end(),//range bind2nd(less<int>(), 50)), //remove criterion coll.end());

5.7 返回第一個偶數

pos = find_if(coll.begin(), coll.end(), //range not1(bind2nd(modulus<int>(), 2)));

上面幾個例子都還是挺使用的,返回第一偶數么,怎么看怎么奇怪,沒有關系,我們來看一個不奇怪的:

5.8 調整數組順序,使得奇數位于偶數前面

stable_partition(v.begin(), v.end(), bind2nd(modulus<int>(), 2));

關于這里用到的泛型算法,如果還有不熟悉的,可以參考這里

5.9 mem_fun_ref 與mem_fun 的區別以及用法

  • mem_fun_ref:調用某個對象的成員函數
  • mem_fun:功能和mem_fun_ref 一樣,如果容器里存放的是指向對象的指針,而不是對象,則應該使用mem_fun

下面來看一個使用mem_fun_ref 的例子,假設我們定義了一個類Person,并且定義了一個print 的成員函數,容器coll 里存放了coll.size() 個Person 對象,現在要調用每個對象的print 成員函數,那么我們就可以像下面這樣。

class Person { public: ... void print() const { std::cout << name << std::endl; } void printWithPrefix(std::string prefix) const { std::cout << prefix << name << std::endl; } private: std::string name; }; void foo(const std::vector<Person> &coll) { for_each(coll.begin(), coll.end(), mem_fun_ref(&Person::print)); }

我們不能直接把一個成員函數傳遞給一個算法,所以這里必須運用函數適配器,下面這種做法會導致編譯錯誤。

for_each(coll.begin(), coll.end(), &Person::print); //ERROR

通過使用函數適配器,我們還可以像被調用的成員函數傳遞一個參數。如下所示:

//call member function printWithPrefix() for each elementfor_each(coll.begin(), coll.end(), bind2nd(mem_fun_ref(&Person::printWithPrefix), "person:"));

5.10 ptr_fun

ptr_fun 使得我們能夠在其他函數適配器中使用一般函數,加入你自己定義了一個函數check(),用于檢驗容器中的中的元素是否符合某種條件,你就可以這樣:

pos = find_if(coll.begin(), coll.end(), not1(ptr_fun(check)));

這里不能使用not1(check),因為not1()需要用到由仿函數提供的某些特殊型別.

第二種用法是,當你有一個雙參數的全局函數,又想把它當做一個單參數函數來使用,可以用如下語句:

//find first string that is not empty pos = find_if(coll.begin(), coll.end(), bind2nd(ptr_fun(strcmp),""));

6.讓自定義的仿函數也可以使用函數適配器

你可以編寫自己的仿函數,但如果希望它們能夠和函數適配器搭配運用,就必須滿足某些條件:必須提供一些型別成員來反映其參數和返回值的型別。為了方便我們,C++標準庫提供了一些結構如下:

轉載:http://mingxinglai.com/cn/2012/09/function-object/


總結

以上是生活随笔為你收集整理的仿函数(函数对象)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。