zoukankan      html  css  js  c++  java
  • ###STL学习--函数对象

    点击查看Evernote原文

    #@author:       gr
    #@date:         2014-08-13
    #@email:        forgerui@gmail.com
    

    在stl中,函数对象被大量地使用,用以提高代码的通用性及效率。stl也提供了一些常用的函数对象类型。

    ###stl学习
     |--迭代器
     |--类属算法
     |--容器
       |--vector
       |--deque
       |--list
       |--set
       |--map
     |--函数对象
     |--适配器
     |--分配器

    一、Contents

    1. 所谓函数对象

    函数对象是行为类似函数的对象。一个类对象,表现出一个函数的特征,即通过对象名+(参数列表)的方式使用一个类对象。

    2. 初见函数对象

    int sum = add(a, b)可以看做是调用add函数或者使用函数对象,如下:

    //1. 完全可以看做是调用add函数
    int sum = add(a, b);
    //2. 当然也可以看作是使用函数对象,可以通过如下的定义:
    Template <class T>
    class Add{
    public:
        T operator() (T a, T b){
            return a + b;
        }
    };
    Sum<int> add;s
    int sum = add(a, b);
    

    3. 为何要使用函数对象

    那么为什么不使用更简单的函数,而选择看起来更复杂的函数对象呢?
    在一些情况下,为了使程序富于变化,增加程序的通用性,有时需要将函数当作参数传递,这就需要使用函数指针。
    stl类属算法中有一个accumulate函数,其中需要传递一个函数。如下:

    //accumulate函数实现,最后一个参数是函数指针
    template<typename InputIterator, typename T>
    T accumulate(InputIterator first, InputIterator last, T init, T (*binary_function)(T a, T b)){
        while(first != last){
            init = binary_function(init, *first++);
        }
        return init;
    }
    //声明的函数
    int product(int a, int b){ return a*b;}
    int main(){
        int arr[] = {1, 3, 5, 2, 1};
        vector<int> vec(arr, arr+6);
        //传递声明的函数指针
        int product = accumulate(vec.begin(), vec.end(), 1, &product);
    }
    

    这样的实现有个问题是通用性不强。函数指针原型可以写为

    T (*binary_function) (T a, T b);
    

    这样的函数可以和int product(int, int)匹配,但如果T类型很大,为了提高效率,需要将上面的语句写为如下:

    T (*binary_function) (const T& a, const T& b);
    

    则product将**无法与之匹配××,此时必须将函数重写为

    int product(const int&, const int&);
    

    另外一个问题在于效率,必须通过指针才能调用这个函数,所以无法使用内联的方式,如果要执行的函数很小,进行一次函数调用将会有相对大的额外开销,而如果这个函数调用是在一个循环中,可以想象出其对效率有严重的影响。

    4. 使用函数对象解决问题

    现在修改accumulate函数,使用函数对象作为参数。

    template <typename InputIterator, typename T, typename FunObj>
    T accumulate(InputIterator first, InputIterator last, T init, FunObj obj){
        while(first != last){
            init = obj(init, *first++);
        }
        return init;
    }
    

    使用这种定义的优点是,可以传递各式各样的类对象,并且可以对operator()进行重载,以匹配多种类型的函数调用,而函数指针则只能接受指定类型的函数,这无疑提高了通用性

    另外,编译器可以对operator()进行内联,从而取消调用函数的开销。

    More,使用类对象可以提供额外信息,类对象可以有数据成员,可以记录一些状态,这样可以本地封装信息,而无需采用静态或全局数据来实现...

    5. stl中提供的函数对象类

    • 算术运算类
      plus, minus, multiplies, divides, modules, negate
    • 比较运算
      equal_to, not_equal_to, greater, less, greater_equal, less_equal
    • 逻辑运算
      logical_and, logical_or, logical_not

    二、Miscellany

    @author gr  
    @mail   forgerui@gmail.com
  • 相关阅读:
    判断一个字符串是否为回文串
    读<大道至简>软件工程实践者的思想有感
    Java学习10.23(设置页面的编码方式1)
    Java学习10.25(javaweb在界面输出2)
    【搜索】C000_LG_奶酪(bfs)
    【并查集】B001_AW_自动程序分析(不要求顺序时的离散化)
    b_aw_信息传递 & 银河英雄传说(并查集暴力求环 / 记忆化 | 带权并查集)
    b_pat_团伙头目(并查集/dfs+字符串整形互相映射)
    【堆】C003_AW_接水问题(暴力 / 堆)
    【并查集】C002_AW_樱桃网 & 打击犯罪(最下生成树 / dfs / 并查集求连通块)
  • 原文地址:https://www.cnblogs.com/gr-nick/p/3973137.html
Copyright © 2011-2022 走看看