zoukankan      html  css  js  c++  java
  • C++中的函数对象(一)

      STL中的函数对象,大多数STL类属算法(以及某些容器类)可以以一个函数对象作为参数。引入函数对象的目的是为了使算法的功能富于变化,从而增强算法的通用性。

      所谓函数对象,是指一段代码实体,它可以不带参数,也可以带有若干参数,其功能是获得一个值,或者改变操作的状态。在C++编程中,任何普通的函数都满足这个定义,而且,任何一个重载了运算符operator()的类的对象也都满足这一定义,称为函数对象

    普通函数

    int multfun(int x, int y)
    {
        return x*y;
    }

    或者下面所定义的multiply类型的对象multfunobj

    class multiply{
    public:
        int operator()(int x, int y) const {return x*y;}    
    };

    multiply multfunobj;

    上面的两种方式,都可以用下面的方式调用:

    int product1 = multfun(3, 7);

    int product2 = multfunobj(3, 7);

    1.通过函数指针传递函数参数

    #include <iostream>
    #include <cassert>
    #include <vector>
    
    using namespace std;
    
    int multfun(int x, int y)
    {
        return x*y;
    }
    
    template <typename InputIterator, typename T>
    T accumulate1(InputIterator first, InputIterator last, T init, T(*binary_function)(T x, T y))
    {
        while(first != last)
        {
            init = (*binary_function)(init, *first);
            ++first;    
        }
        return init;
    }
    
    int main()
    {
        cout << "Demonstrating function pointer passing." << endl;
        int x[5] = {2, 3, 5, 7, 11};
        vector<int> vector1(&x[0], &x[5]);
    
        int product = accumulate1(vector1.begin(), vector1.end(), 1, &multfun);
        assert (product == 2310);
        cout << "---- OK."<<endl;
        
        return 0;
    }

    输出--- OK

    这种传统实现方式的一个基本问题是其通用性不够强,例如,函数指针原型可以写成

    T (*binary_function)(T x, T y);

    并且可以和int multifun(int ,int)匹配,但是,如果写成 T (*binary_function)(const T& x, const T& y);以便使其在T类对象比较大的情况下具有较高效率,则multifun将无法与之匹配,此时必须以原型 int multifun(const int&, cosnt int& )对函数进行重写。

    另外个问题,在于效率上的,在accumulate1中,必须通过一个指针才能访问以参数形式传递进来的函数,而且只能外联(out of line)地调用该函数(首先向函数传递参数,然后把控制权移交给函数,并且把返回值拷贝到调用域中,最后把控制移交给函数的调用域)。在被调用函数为mutifun的情况下,函数内部的计算只需要一两个机器指令,而这些步骤的开销却要大的多。

    2.通过模板参数定义函数对象的优越性

    #include <iostream>
    #include <cassert>
    #include <vector>
    
    using namespace std;
    
    template <typename InputIterator, typename T, typename BinaryFunction>
    T accumulate (InputIterator first, InputIterator last, T init, BinaryFunction binary_function)
    {
        while(first != last)
        {
            init = binary_function(init, *first);
            ++first;
        }
    
        return init;
    }
    
    class multiply{
    public:
        int operator()(int x, int y) const {return x*y;}    
    };
        
    multiply multfunobj;
    
    int main()
    {
        cout << "Demonstrating function pointer passing." << endl;
        int x[5] = {2, 3, 5, 7, 11};
        vector<int> vector1(&x[0], &x[5]);
    
        int product = accumulate(vector1.begin(), vector1.end(), 1, multfunobj);
        assert(product == 2310);
        cout << "------ OK"<< endl;
        return 0;
    }

     accumulate的这种定义下,该函数的最后一个实际参数只需要满足:带两个参数,其类型分别为T1和T2,其中类型T可以转换为T1,inputIterator的值类型可以转换为T2,

    且该参数的返回值类型可以转换为T,这样一来,与函数指针传递的过于严格的类型要求相比,这样的定义方式可以接受更多种类的函数原型。

      在性能方面,由于通过模板参数和重载operator()定义了可以作为参数传递的函数对象,因此编译器可以把binary_function函数调用内联(inline)在accumulate函数体中,

    从而彻底消除了指针解析和外联调用所带来的额外开销。

      此外,类定义中还可以定义一些额外的信息,这样类的对象就携带了一些额外的信息。

      接下来我们就对类对象的一些基本用法进行简单举例。

    参考《标准模板库自修教程与参考手册——STL进行C++编程》

    参考:http://blog.csdn.net/bonchoix/article/details/8050627

  • 相关阅读:
    较简单的date转化成格式化的timeString
    字符串截取的用法
    UIImageView的图片轮播属性
    label.lineBreakMode设置lable中文字过长时的显示格式,其中可以有末尾以省略号显示。
    UIImageView的contentMode属性
    iOS开发----关于导航条的研究
    iOS 开发对图片进行处理
    设置按钮中的图片的旋转,并且旋转之后不变形
    调整按钮的子控件titleLable和imageView的间距的属性和用法
    ios开发之--数据库开发
  • 原文地址:https://www.cnblogs.com/hpcpp/p/7107197.html
Copyright © 2011-2022 走看看