• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            兔子的技術博客

            兔子

               :: 首頁 :: 聯系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評論

            閱讀排行榜

            評論排行榜

                  STL是C++標準庫的重要組成部分之一,它不僅是一個可復用的組件庫,更是一個包含算法與數據結構的軟件框架,同時也是C++泛型編程的很好例子。STL中運用了許多C++的高級技術。本文介紹函數對象,其實是接上一篇的話題,因為函數對象本質上還是重載操作符。主要參考了《C++ Primer》和《STL源碼剖析》。

                  可以為類類型的對象重載函數調用操作符,定義了調用操作符的類,其對象稱之為函數對象(function object),即它們的行為類似函數對象。這是《C++ Primer》中的定義。下面通過一個例子來引出函數對象的使用。在我的解題筆記系列中,有一篇文章 解題筆記(16)——幾個數字的問題,其中第四個問題是調整數組順序使奇數位于偶數前面(數組)。輸入一個整數數組,調整數組中數字的順序,使得所有奇數位于數組的前半部分。所有偶數位于數組的后半部分。要求時間復雜度為O(n)。這個問題不難,其中用到了函數指針。代碼如下:

            1. bool IsOdd(int x)    
            2. {    
            3.     return (x & 1)? truefalse;    
            4. }    
            5. //函數功能 : 調整數組順序使奇數位于偶數前面    
            6. //函數參數 : pArray指向數組的指針,nLen為數組長度    
            7. //返回值 :   無    
            8. void PartionArray(int *pArray, int nLen, bool (*func)(int))    
            9. {    
            10.     int i = -1;    
            11.     for(int j = 0; j < nLen; j++)    
            12.     {    
            13.         if(func(pArray[j])) //滿足調整條件    
            14.         {    
            15.             i++;    
            16.             int tmp = pArray[j];    
            17.             pArray[j] = pArray[i];    
            18.             pArray[i] = tmp;    
            19.         }    
            20.     }    
            21. }   

                  傳遞一個函數指針的好處是,可以很方便的修改調整的條件,這個問題希望將奇數放在前面,偶數放在后面。如果有另外一個問題,希望將正數放前面,負數放后面,那么只需定義新的調整函數,類似 IsOdd,然后將它作為參數傳遞給PartionArray函數即可。

                  這里其實也可以使用函數對象,代碼如下:

            1. #include <iostream>  
            2. using namespace std;  
            3.   
            4. //函數對象  
            5. template<class T>  
            6. struct IsOdd  
            7. {  
            8.     bool operator() (T x){  
            9.         return (x & 1)?truefalse;  
            10.     }  
            11. };  
            12. //函數功能 : 調整數組順序使奇數位于偶數前面    
            13. //函數參數 : pArray指向數組的指針,nLen為數組長度    
            14. //返回值 :   無    
            15. template <class T, class F>  
            16. void PartionArray(T *pArray, int nLen, F func)  
            17. {    
            18.     int i = -1;    
            19.     for(int j = 0; j < nLen; j++)    
            20.     {    
            21.         if(func(pArray[j])) //滿足調整條件    
            22.         {    
            23.             i++;    
            24.             T tmp = pArray[j];    
            25.             pArray[j] = pArray[i];    
            26.             pArray[i] = tmp;    
            27.         }    
            28.     }    
            29. }    
            30. //測試用例  
            31. int main()  
            32. {  
            33.     short a[] = {1,2,3,4,5,6};  
            34.     long b[] = {1,2,3,4,5,6};  
            35.     PartionArray(a, 6, IsOdd<short>());   
            36.     PartionArray(b, 6, IsOdd<long>());   
            37.     return 0;  
            38. }  

                   相比函數指針,函數對象的優勢在于能很好的滿足STL的抽象要求,同時更為靈活。上面這個例子算是一個引子,引出STL中函數對象的運用。

                   STL中的函數對象并不是孤立的,而是與STL的算法緊密聯系在一起。舉個簡單的例子就明白了,比如我們希望利用STL的算法為一個數組排序,我們可以這樣做。

            1. #include <iostream>  
            2. #include <algorithm>  
            3. using namespace std;  
            4. int main()  
            5. {  
            6.     int a[] = {1,3,2,4,5,7};  
            7.     sort(&a[0], &a[6]);  
            8.     for(int i = 0; i < 6; i++)  
            9.         cout<<a[i]<<' ';  
            10.     cout<<endl;  
            11.     return 0;  
            12. }  
                   這個排序算法默認是遞增排序,那么如果希望是遞減排序呢?很方便,在函數實參中加入一個函數對象即可。記住需包含頭文件 #include <functional>

            1. #include <iostream>  
            2. #include <functional>  
            3. #include <algorithm>  
            4. using namespace std;  
            5. int main()  
            6. {  
            7.     int a[] = {1,3,2,4,5,7};  
            8.     sort(&a[0], &a[6], greater<int>());  
            9.     for(int i = 0; i < 6; i++)  
            10.         cout<<a[i]<<' ';  
            11.     cout<<endl;  
            12.     return 0;  
            13. }  

                     可以說在STL中,函數對象扮演著重要的角色,發揮著巨大的作用。下面列出了幾個常用的函數對象,摘自HP的STL源碼,做了部分修改。STL定義了兩個類,作為一元操作和二元操作的基類,這兩個基類僅僅是使用了內嵌型別技術,為什么要這樣子呢?后面介紹函數適配器時有說明,可以看到它的強大之處。

            1. //用來定義一元操作的參數類別和返回值類別  
            2. template <class Arg, class Result>  
            3. struct unary_function {  
            4.     typedef Arg argument_type;  //內嵌型別技術  
            5.     typedef Result result_type;  
            6. };  
            7. //用來定義二元操作的參數類別和返回值類別  
            8. template <class Arg1, class Arg2, class Result>  
            9. struct binary_function {  
            10.     typedef Arg1 first_argument_type;  
            11.     typedef Arg2 second_argument_type;  
            12.     typedef Result result_type;  
            13. };  
            14.   
            15. //一元操作,就兩個  
            16. template <class T>  
            17. struct negate : public unary_function<T, T> {  
            18.     T operator()(const T& x) const { return -x; }  
            19. };  
            20. template <class T>  
            21. struct logical_not : public unary_function<T,bool> {  
            22.     bool operator()(const T& x) const { return !x; }  
            23. };  
            24. //加減乘除取模  
            25. template <class T>  
            26. struct plus : public binary_function<T, T, T> {  
            27.     T operator()(const T& x, const T& y) const { return x + y; }  
            28. };  
            29. template <class T>  
            30. struct minus : public binary_function<T, T, T> {  
            31.     T operator()(const T& x, const T& y) const { return x - y; }  
            32. };  
            33. template <class T>  
            34. struct multiplies : public binary_function<T, T , T> {  
            35.     T operator()(const T& x, const T& y) const { return x * y; }  
            36. };  
            37. template <class T>  
            38. struct divides : public binary_function<T ,T, T> {  
            39.     T operator()(const T& x, const T& y) const { return x / y; }  
            40. };  
            41. template <class T>  
            42. struct modulus : public binary_function<T, T, T> {  
            43.     T operator()(const T& x, const T& y) const { return x % y; }  
            44. };  
            45. //關系運算  
            46. template <class T>  
            47. struct equal_to : public binary_function<T, T, bool> {  
            48.     bool operator()(const T& x, const T& y) const { return x == y; }  
            49. };  
            50. template <class T>  
            51. struct not_equal_to : public binary_function<T, T,bool> {  
            52.     bool operator()(const T& x, const T& y) const { return x != y; }  
            53. };  
            54. template <class T>  
            55. struct greater : public binary_function<T, T, bool> {  
            56.     bool operator()(const T& x, const T& y) const { return x > y; }  
            57. };  
            58. template <class T>  
            59. struct less : public binary_function<T, T, bool> {  
            60.     bool operator()(const T& x, const T& y) const { return x < y; }  
            61. };  
            62. template <class T>  
            63. struct greater_equal : public binary_function<T, T, bool> {  
            64.     bool operator()(const T& x, const T& y) const { return x >= y; }  
            65. };  
            66. template <class T>  
            67. struct less_equal : public binary_function<T, T, bool> {  
            68.     bool operator()(const T& x, const T& y) const { return x <= y; }  
            69. };  
            70. //邏輯運算  
            71. template <class T>  
            72. struct logical_and : public binary_function<T, T, bool>{  
            73.     bool operator()(const T& x, const T& y) const { return x && y; }  
            74. };  
            75. template <class T>  
            76. struct logical_or : public binary_function<T, T, bool>  
            77. {  
            78.   bool operator()(const T& x, const T& y) const { return x || y; }  
            79. };  

                  上面這些函數對象都比較簡單,接下來介紹幾個稍微復雜點的,它們被稱為函數適配器(function adapter),用于特化和擴展一元和二元函數對象。分為兩類,第一是綁定器(binder),它通過將一個操作數綁定到給定值而將二元函數對象轉換為一元函數。第二是求反器(negator),它將謂詞函數對象的真值求反。這些定義來自《C++ Primer》一書。書上還給了兩個例子,這里羅列一下:

            1. #include <iostream>  
            2. #include <functional>  
            3. #include <vector>  
            4. #include <algorithm>  
            5. using namespace std;  
            6. int main()  
            7. {  
            8.     vector<int> vec(10, 1);  
            9.     int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));       //求容器中小于等于10的元素個數  
            10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素個數,正好是上面結果的取反  
            11.     cout<<count1<<' '<<count2<<endl;  //10 0  
            12.     return 0;  
            13. }  
                    下面分析一下STL是如何實現函數適配器的,先給出STL的源碼。已經整理過了。

            1. //綁定第一個參數  
            2. template <class Operation>   
            3. class binder1st: public unary_function<typename Operation::second_argument_type, typename Operation::result_type> {  
            4. public:  
            5.     binder1st(const Operation& x, const typename Operation::first_argument_type& y) : op(x), value(y) {} //構造函數  
            6.     typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const {  
            7.         return op(value, x);  //固定第一個參數  
            8.     }  
            9. protected:  
            10.     Operation op;  
            11.     typename Operation::first_argument_type value;  
            12. };  
            13. //綁定第二個參數  
            14. template <class Operation>   
            15. class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
            16. public:  
            17.     binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {}  
            18.     typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {  
            19.         return op(x, value);  //固定第二個參數  
            20.     }  
            21. protected:  
            22.     Operation op;  
            23.     typename Operation::second_argument_type value;  
            24. };  
            25. //外部接口  
            26. template <class Operation, class T>  
            27. inline binder1st<Operation> bind1st(const Operation& fn, const T& x) {  
            28.     typedef typename Operation::first_argument_type Arg1_type;  
            29.     return binder1st<Operation>(fn,Arg1_type(x));  
            30. }  
            31. //外部接口  
            32. template <class Operation, class T>  
            33. inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
            34.     typedef typename Operation::second_argument_type Arg2_type;  
            35.     return binder2nd<Operation>(fn, Arg2_type(x));  
            36. }  
            1. //一元操作求反  
            2. template <class Predicate>  
            3. class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
            4. protected:  
            5.     Predicate pred;  
            6. public:  
            7.     explicit unary_negate(const Predicate& x) : pred(x) {}  
            8.     bool operator()(const typename Predicate::argument_type& x) const {  
            9.     return !pred(x);  
            10.   }  
            11. };  
            12. //二元操作求反  
            13. template <class Predicate>   
            14. class binary_negate : public binary_function<typename Predicate::first_argument_type, typename Predicate::second_argument_type,bool> {  
            15. protected:  
            16.     Predicate pred;  
            17. public:  
            18.     explicit binary_negate(const Predicate& x) : pred(x) {}  
            19.     bool operator()(const typename Predicate::first_argument_type& x, const typename Predicate::second_argument_type& y) const {  
            20.         return !pred(x, y);   
            21.     }  
            22. };  
            23. //外部接口  
            24. template <class Predicate>  
            25. inline unary_negate<Predicate> not1(const Predicate& pred)  
            26. {  
            27.     return unary_negate<Predicate>(pred);  
            28. }  
            29. //外部接口  
            30. template <class Predicate>  
            31. inline binary_negate<Predicate> not2(const Predicate& pred)  
            32. {  
            33.     return binary_negate<Predicate>(pred);  
            34. }  
                      到這里,我們可以回答之前的一個問題,就是STL為什么要定義兩個基類,里面僅僅是內嵌型別。通過上面代碼,不難發現,原來是用來萃取函數對象所操作的數據類型。比如 binder1st 這個類,它的模板中只有一個形參,它繼承自unary_function,而unary_function的模板有兩個形參。如何實現這種繼承關系呢?內嵌型別技術,因為binder1st 的模板實參是個函數對象,繼承自unary_function或binary_function,通過內嵌型別技術很容易萃取出數據類型。

                     再進一步,函數適配器是如何工作的呢?

            1. include <iostream>  
            2. #include <functional>  
            3. #include <vector>  
            4. #include <algorithm>  
            5. using namespace std;  
            6. int main()  
            7. {  
            8.     vector<int> vec(10, 1);  
            9.     int count1 = count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10));       //求容器中小于等于10的元素個數  
            10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素個數,正好是上面函數的取反  
            11.     cout<<count1<<' '<<count2<<endl;  //10 0  
            12.     return 0;  
            13. }  
                    還是以這個程序為例,介紹一下count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10))具體執行。首先執行bind2nd(less_equal<int>(), 10)這個函數,這個函數會返回一個binder2nd的函數對象,注意構造這個函數對象的時候,binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {} 。第二個參數value的值設置為10,而第一個參數op設置成less_equal<int>()這個函數對象。

                   接著count_if 執行時,下面是它的源碼。執行時,pred(*first)其實就是binder2nd中的運算,而這個運算的第二個參數是固定的,也就是10,所以pred只傳遞了一個實參進去就可以了。

            1. template <class InputIter, class Predicate, class Size>  
            2. void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {  
            3.     for ( ; first != last; ++first)  
            4.         if (pred(*first))  
            5.             ++n;  
            6. }  
            7. template <class InputIter, class Predicate>  
            8. typename iterator_traits<InputIter>::difference_type count_if(InputIter first, InputIter last, Predicate pred) {  
            9.     typename iterator_traits<InputIter>::difference_type n = 0;  
            10.     for ( ; first != last; ++first)  
            11.         if (pred(*first))  
            12.             ++n;  
            13.     return n;  
            14. }  
                    下面把上述綜合起來,通過修改STL,寫個完整的測試程序。如下所示,注意這里用的都是自定義的代碼,沒有包含STL的函數對象和函數。

            1. #include <iostream>  
            2. #include <vector>  
            3. using namespace std;  
            4.   
            5. //count_if函數  
            6. template <class InputIter, class Predicate, class Size>  
            7. void count_if(InputIter first, InputIter last, Predicate pred, Size& n) {  
            8.     for ( ; first != last; ++first)  
            9.         if (pred(*first))  
            10.             ++n;  
            11. }  
            12. //用來定義一元操作的參數類別和返回值類別  
            13. template <class Arg, class Result>  
            14. struct unary_function {  
            15.     typedef Arg argument_type;  
            16.     typedef Result result_type;  
            17. };  
            18. //用來定義二元操作的參數類別和返回值類別  
            19. template <class Arg1, class Arg2, class Result>  
            20. struct binary_function {  
            21.     typedef Arg1 first_argument_type;  
            22.     typedef Arg2 second_argument_type;  
            23.     typedef Result result_type;  
            24. };  
            25. //本測試之用到關系函數對象  
            26. template <class T>  
            27. struct less_equal : public binary_function<T, T, bool> {  
            28.     bool operator()(const T& x, const T& y) const { return x <= y; }  
            29. };  
            30. //綁定第二個參數  
            31. template <class Operation>   
            32. class binder2nd: public unary_function<typename Operation::first_argument_type,typename Operation::result_type> {  
            33. public:  
            34.     binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) { cout<<"binder2nd Constructor"<<endl; }  
            35.     typename Operation::result_type operator()(const typename Operation::first_argument_type& x) const {  
            36.         cout<<"binder2nd's operator()"<<endl;  
            37.         return op(x, value);  //固定第二個參數  
            38.     }  
            39. protected:  
            40.     Operation op;  
            41.     typename Operation::second_argument_type value;  
            42. };  
            43. //外部接口  
            44. template <class Operation, class T>  
            45. inline binder2nd<Operation> bind2nd(const Operation& fn, const T& x) {  
            46.     typedef typename Operation::second_argument_type Arg2_type;  
            47.     return binder2nd<Operation>(fn, Arg2_type(x));  
            48. }  
            49. //一元操作求反  
            50. template <class Predicate>  
            51. class unary_negate: public unary_function<typename Predicate::argument_type, bool> {  
            52. protected:  
            53.     Predicate pred;  
            54. public:  
            55.     explicit unary_negate(const Predicate& x) : pred(x) { cout<<"unary_negate Constructor"<<endl; }  
            56.     bool operator()(const typename Predicate::argument_type& x) const {  
            57.     cout<<"unary_negate's operator()"<<endl;  
            58.     return !pred(x);  
            59.   }  
            60. };  
            61. //外部接口  
            62. template <class Predicate>  
            63. inline unary_negate<Predicate> not1(const Predicate& pred)  
            64. {  
            65.     return unary_negate<Predicate>(pred);  
            66. }  
            67. //測試程序  
            68. int main()  
            69. {  
            70.     vector<int> vec(10, 1);  
            71.     int count1 = 0, count2 = 0;  
            72.     count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10),count1);       //求容器中小于等于10的元素個數  
            73.     count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)),count2); //求容器中不小于等于10的元素個數,正好是上面函數的取反  
            74.     cout<<count1<<' '<<count2<<endl;  //10 0  
            75.     return 0;  
            76. }  
            出處 http://blog.csdn.net/wuzhekai1985
            原文:http://blog.csdn.net/wuzhekai1985/article/details/6658940
            posted on 2011-09-06 10:42 會飛的兔子 閱讀(1370) 評論(0)  編輯 收藏 引用 所屬分類: C++庫,組件
            久久亚洲欧美国产精品| 国内精品久久久久久99| 久久精品中文字幕久久| 久久精品欧美日韩精品| 一本一本久久A久久综合精品| 久久精品国产欧美日韩99热| 午夜肉伦伦影院久久精品免费看国产一区二区三区| 久久婷婷成人综合色综合| 中文字幕久久精品无码| 狠狠色婷婷久久一区二区| 久久久无码精品亚洲日韩京东传媒| 香蕉99久久国产综合精品宅男自| 午夜精品久久久久| 免费无码国产欧美久久18| 无码AV波多野结衣久久| 久久婷婷五月综合97色一本一本| 97久久久久人妻精品专区| 日本久久久精品中文字幕| 久久久久亚洲?V成人无码| 中文成人久久久久影院免费观看| 国色天香久久久久久久小说| 久久人人爽人人爽人人片av高请 | 日韩人妻无码精品久久免费一| 亚洲AV乱码久久精品蜜桃| 狠狠88综合久久久久综合网| 久久久久中文字幕| 久久九九免费高清视频| 中文字幕日本人妻久久久免费| 精品国产乱码久久久久久郑州公司| 嫩草影院久久99| 久久婷婷五月综合97色直播| 国产精品久久久久久久久久影院| 久久人爽人人爽人人片AV| 久久国产精品免费| 亚洲中文字幕无码一久久区| 四虎国产精品免费久久5151| 日韩亚洲国产综合久久久| 精品久久无码中文字幕| 亚洲午夜久久久| 久久精品国产一区| 久久这里只有精品首页|