• <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>

            兔子的技術(shù)博客

            兔子

               :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
              202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

            留言簿(10)

            最新評論

            閱讀排行榜

            評論排行榜

                  STL是C++標(biāo)準(zhǔn)庫的重要組成部分之一,它不僅是一個(gè)可復(fù)用的組件庫,更是一個(gè)包含算法與數(shù)據(jù)結(jié)構(gòu)的軟件框架,同時(shí)也是C++泛型編程的很好例子。STL中運(yùn)用了許多C++的高級技術(shù)。本文介紹函數(shù)對象,其實(shí)是接上一篇的話題,因?yàn)楹瘮?shù)對象本質(zhì)上還是重載操作符。主要參考了《C++ Primer》和《STL源碼剖析》。

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

            1. bool IsOdd(int x)    
            2. {    
            3.     return (x & 1)? truefalse;    
            4. }    
            5. //函數(shù)功能 : 調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面    
            6. //函數(shù)參數(shù) : pArray指向數(shù)組的指針,nLen為數(shù)組長度    
            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])) //滿足調(diào)整條件    
            14.         {    
            15.             i++;    
            16.             int tmp = pArray[j];    
            17.             pArray[j] = pArray[i];    
            18.             pArray[i] = tmp;    
            19.         }    
            20.     }    
            21. }   

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

                  這里其實(shí)也可以使用函數(shù)對象,代碼如下:

            1. #include <iostream>  
            2. using namespace std;  
            3.   
            4. //函數(shù)對象  
            5. template<class T>  
            6. struct IsOdd  
            7. {  
            8.     bool operator() (T x){  
            9.         return (x & 1)?truefalse;  
            10.     }  
            11. };  
            12. //函數(shù)功能 : 調(diào)整數(shù)組順序使奇數(shù)位于偶數(shù)前面    
            13. //函數(shù)參數(shù) : pArray指向數(shù)組的指針,nLen為數(shù)組長度    
            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])) //滿足調(diào)整條件    
            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. }  

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

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

            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. }  
                   這個(gè)排序算法默認(rèn)是遞增排序,那么如果希望是遞減排序呢?很方便,在函數(shù)實(shí)參中加入一個(gè)函數(shù)對象即可。記住需包含頭文件 #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中,函數(shù)對象扮演著重要的角色,發(fā)揮著巨大的作用。下面列出了幾個(gè)常用的函數(shù)對象,摘自HP的STL源碼,做了部分修改。STL定義了兩個(gè)類,作為一元操作和二元操作的基類,這兩個(gè)基類僅僅是使用了內(nèi)嵌型別技術(shù),為什么要這樣子呢?后面介紹函數(shù)適配器時(shí)有說明,可以看到它的強(qiáng)大之處。

            1. //用來定義一元操作的參數(shù)類別和返回值類別  
            2. template <class Arg, class Result>  
            3. struct unary_function {  
            4.     typedef Arg argument_type;  //內(nèi)嵌型別技術(shù)  
            5.     typedef Result result_type;  
            6. };  
            7. //用來定義二元操作的參數(shù)類別和返回值類別  
            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. //一元操作,就兩個(gè)  
            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. //關(guān)系運(yùn)算  
            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. //邏輯運(yùn)算  
            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. };  

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

            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的元素個(gè)數(shù)  
            10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素個(gè)數(shù),正好是上面結(jié)果的取反  
            11.     cout<<count1<<' '<<count2<<endl;  //10 0  
            12.     return 0;  
            13. }  
                    下面分析一下STL是如何實(shí)現(xiàn)函數(shù)適配器的,先給出STL的源碼。已經(jīng)整理過了。

            1. //綁定第一個(gè)參數(shù)  
            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) {} //構(gòu)造函數(shù)  
            6.     typename Operation::result_type operator()(const typename Operation::second_argument_type& x) const {  
            7.         return op(value, x);  //固定第一個(gè)參數(shù)  
            8.     }  
            9. protected:  
            10.     Operation op;  
            11.     typename Operation::first_argument_type value;  
            12. };  
            13. //綁定第二個(gè)參數(shù)  
            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);  //固定第二個(gè)參數(shù)  
            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. }  
                      到這里,我們可以回答之前的一個(gè)問題,就是STL為什么要定義兩個(gè)基類,里面僅僅是內(nèi)嵌型別。通過上面代碼,不難發(fā)現(xiàn),原來是用來萃取函數(shù)對象所操作的數(shù)據(jù)類型。比如 binder1st 這個(gè)類,它的模板中只有一個(gè)形參,它繼承自unary_function,而unary_function的模板有兩個(gè)形參。如何實(shí)現(xiàn)這種繼承關(guān)系呢?內(nèi)嵌型別技術(shù),因?yàn)閎inder1st 的模板實(shí)參是個(gè)函數(shù)對象,繼承自unary_function或binary_function,通過內(nèi)嵌型別技術(shù)很容易萃取出數(shù)據(jù)類型。

                     再進(jìn)一步,函數(shù)適配器是如何工作的呢?

            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的元素個(gè)數(shù)  
            10.     int count2 = count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10))); //求容器中不小于等于10的元素個(gè)數(shù),正好是上面函數(shù)的取反  
            11.     cout<<count1<<' '<<count2<<endl;  //10 0  
            12.     return 0;  
            13. }  
                    還是以這個(gè)程序?yàn)槔榻B一下count_if(vec.begin(), vec.end(), bind2nd(less_equal<int>(), 10))具體執(zhí)行。首先執(zhí)行bind2nd(less_equal<int>(), 10)這個(gè)函數(shù),這個(gè)函數(shù)會(huì)返回一個(gè)binder2nd的函數(shù)對象,注意構(gòu)造這個(gè)函數(shù)對象的時(shí)候,binder2nd(const Operation& x, const typename Operation::second_argument_type& y) : op(x), value(y) {} 。第二個(gè)參數(shù)value的值設(shè)置為10,而第一個(gè)參數(shù)op設(shè)置成less_equal<int>()這個(gè)函數(shù)對象。

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

            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,寫個(gè)完整的測試程序。如下所示,注意這里用的都是自定義的代碼,沒有包含STL的函數(shù)對象和函數(shù)。

            1. #include <iostream>  
            2. #include <vector>  
            3. using namespace std;  
            4.   
            5. //count_if函數(shù)  
            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. //用來定義一元操作的參數(shù)類別和返回值類別  
            13. template <class Arg, class Result>  
            14. struct unary_function {  
            15.     typedef Arg argument_type;  
            16.     typedef Result result_type;  
            17. };  
            18. //用來定義二元操作的參數(shù)類別和返回值類別  
            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. //本測試之用到關(guān)系函數(shù)對象  
            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. //綁定第二個(gè)參數(shù)  
            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);  //固定第二個(gè)參數(shù)  
            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的元素個(gè)數(shù)  
            73.     count_if(vec.begin(), vec.end(), not1(bind2nd(less_equal<int>(), 10)),count2); //求容器中不小于等于10的元素個(gè)數(shù),正好是上面函數(shù)的取反  
            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 會(huì)飛的兔子 閱讀(1383) 評論(0)  編輯 收藏 引用 所屬分類: C++庫,組件
            久久婷婷五月综合97色直播| 99久久国产综合精品女同图片| 久久久久99精品成人片试看| 少妇人妻88久久中文字幕| 国产午夜免费高清久久影院| 久久99精品九九九久久婷婷| 亚洲午夜精品久久久久久app| 99久久精品国内| 久久综合精品国产一区二区三区| 久久人人爽人人爽人人片AV不| 国产精品久久久久无码av | 无码日韩人妻精品久久蜜桃 | 一本一本久久A久久综合精品| 精品久久久久久亚洲| 亚洲午夜无码久久久久小说| 99久久免费国产精品热| 免费久久人人爽人人爽av| 亚洲一本综合久久| 91精品国产色综合久久| 久久久久亚洲AV无码观看| 久久久久亚洲爆乳少妇无| 亚洲国产精久久久久久久| 久久人爽人人爽人人片AV | 97久久超碰国产精品旧版| 久久男人AV资源网站| 亚洲国产精品久久久久婷婷软件| 久久久久久午夜成人影院| 亚洲午夜久久久久久久久久| 国产免费久久精品99re丫y| 久久国产精品免费一区| 99久久婷婷国产综合精品草原| 久久本道伊人久久| 久久综合狠狠色综合伊人| 亚洲国产精品婷婷久久| 国产一区二区精品久久| 国产欧美一区二区久久| 国产精品久久久99| 久久青青草原精品国产软件| 国产99久久久国产精品小说| 久久精品一区二区三区AV| 亚洲av成人无码久久精品|