• 函数对象、 函数对象与容器、函数对象与算法


    一、函数对象

    1、函数对象(function object)也称为仿函数(functor)

    2、一个行为类似函数的对象,它可以没有参数,也可以带有若干参数。
    3、任何重载了调用运算符operator()的类的对象都满足函数对象的特征
    4、函数对象可以把它称之为smart function。
    5、STL中也定义了一些标准的函数对象,如果以功能划分,可以分为算术运算、关系运算、逻辑运算三大类。为了调用这些标准函数对象,需要包含头文件<functional>。


    二、自定义函数对象

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    #include <iostream>
    using namespace std;
    class CFunObj
    {
    public:
        void operator()()
        {
            cout << "hello,function object!" << endl;
        }
    };
    int main()
    {
        CFunObj fo;
        fo();
        CFunObj()();
        return 0;
    }

    注意:CFunObj()(); 表示先构造一个匿名对象,再调用operator();

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    // TEMPLATE CLASS map
    template < class _Kty,
             class _Ty,
             class _Pr = less<_Kty>,
             class _Alloc = allocator<pair<const _Kty, _Ty> > >
    class map
        : public _Tree<_Tmap_traits<_Kty, _Ty, _Pr, _Alloc, false> >
    {
        // ordered red-black tree of {key, mapped} values, unique keys
    };

    假设现在我们这样使用 map< int, string > mapTest; 那么默认的第三个参数 _Pr = less<int>,再者,map 继承的其中一个类

     _Tmap_traits 中有个成员:

     _Pr  comp;// the comparator predicate for keys

    跟踪进insert 函数,其中有这样一句:

    if (_DEBUG_LT_PRED(this->comp, _Key(_Where._Mynode()), this->_Kfn(_Val)))

    已知 #define _DEBUG_LT_PRED(pred, x, y) pred(x, y) 很明显地,comp 在这里当作函数对象使用,传入两个参数,回头看less 类的

    模板实现:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    // TEMPLATE STRUCT less
    template<class _Ty>
    struct less
            : public binary_function<_Ty, _Ty, bool>
    {
        // functor for operator<
        bool operator()(const _Ty &_Left, const _Ty &_Right) const
        {
            // apply operator< to operands
            return (_Left < _Right);
        }
    };

    即实现了operator() 函数,左操作数小于右操作数时返回为真。

    我们也可以在定义的时候传递第三个参数,如map< int, string, greater<int> > mapTest; 则插入时按key 值从大到小排序(less,

     greater 都是STL内置的类,里面实现了operator() 函数),甚至也可以自己实现一个类传递进去,如下面例程所示:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #include <map>
    #include <string>
    #include <iostream>

    using namespace std;

    struct MyGreater
    {
        bool operator()(int left, int right)
        {
            return left > right;
        }
    };

    int main(void)
    {
        map < int, string, /*greater<int> */MyGreater > mapTest;
        mapTest.insert(map<int, string>::value_type(1, "aaaa"));
        mapTest.insert(map<int, string>::value_type(3, "cccc"));
        mapTest.insert(map<int, string>::value_type(2, "bbbb"));


        for (map < int, string, /*greater<int> */MyGreater >::const_iterator it = mapTest.begin(); it != mapTest.end(); ++it)
        {
            cout << it->first << " " << it->second << endl;
        }

        return 0;
    }

    输出为:

    3 cccc

    2 bbbb

    1 aaaa

    MyGreater 类并不是以模板实现,只是比较key 值为int 类型的大小。


    四、函数对象与算法

    在STL一些算法中可以传入函数指针,实现自定义比较逻辑或者计算,同样地这些函数也可以使用函数对象来代替,直接看例程再稍

    作分析:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    #include <vector>
    #include <string>
    #include <iostream>
    #include <algorithm>

    using namespace std;

    void PrintFun(int n)
    {
        cout << n << ' ';
    }

    void Add3(int &n)
    {
        n += 3;
    }

    class PrintObj
    {
    public:
        void operator()(int n)
        {
            cout << n << ' ';
        }
    };

    class AddObj
    {
    public:
        AddObj(int number) : number_(number)
        {

        }
        void operator()(int &n)
        {
            n += number_;
        }

    private:
        int number_;
    };

    class GreaterObj
    {
    public:
        GreaterObj(int number) : number_(number)
        {

        }
        bool operator()(int n)
        {
            return n > number_;
        }
    private:
        int number_;
    };


    int main(void)
    {
        int a[] = {1, 2, 3, 4, 5};
        vector<int> v(a, a + 5);

        /*for_each(v.begin(), v.end(), PrintFun);
        cout<<endl;*/

        for_each(v.begin(), v.end(), PrintObj());
        cout << endl;

        /*for_each(v.begin(), v.end(), Add3);
        for_each(v.begin(), v.end(), PrintFun);
        cout<<endl;*/

        for_each(v.begin(), v.end(), AddObj(5));
        for_each(v.begin(), v.end(), PrintFun);
        cout << endl;


        cout << count_if(a, a + 5, GreaterObj(3)) << endl; //计算大于3的元素个数

        return 0;
    }

    输出为:

    1 2 3 4 5

    6 7 8 9 10

    2

    回顾for_each 的源码,其中有这样一句: _Func(*_ChkFirst); 也就是将遍历得到的元素当作参数传入函数。

    上面程序使用了函数对象,实际上可以这样理解 PrintObj()(*_ChkFirst); 即 PrintObj() 是一个匿名的函数对象,传入参

    count_if 中的 GreaterObj(3) 就类似了,将遍历的元素当作参数传递给operator(), 即若元素比3大则返回为真。



    五、STL内置的函数对象类

    参考:

    C++ primer 第四版
    Effective C++ 3rd
    C++编程规范

  • 相关阅读:
    视频测试序列的下载地址【转】
    RDO、SAD、SATD、λ相关概念【转】
    RGB、YUV和YCbCr介绍【转】
    H.264和HEVC分析软件和工具【转】
    Mysql——Innodb和Myisam概念与数据恢复
    ubuntu个人初始配置记录
    H.264学习笔记6——指数哥伦布编码
    H.264学习笔记5——熵编码之CAVLC
    C/C++语言学习——内存分配管理
    H.264学习笔记4——变换量化
  • 原文地址:https://www.cnblogs.com/alantu2018/p/8471438.html
Copyright © 2020-2023  润新知