首页 > 代码库 > C++中的函数对象(一)

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

C++中的函数对象(一)