什么时候在C ++中使用函数对象?

时间:2010-02-28 15:06:44

标签: c++ stl function-object

我看到函数对象经常与STL算法一起使用。功能对象是否因为这些算法而出现?你什么时候在C ++中使用函数对象?它有什么好处?

7 个答案:

答案 0 :(得分:9)

正如所说的jdv,使用仿函数而不是函数指针,这些函数指针更难以优化和内联编译器;而且,仿函数的一个基本优点是它们可以很容易地保持调用它们之间的状态 1 ,因此它们可以根据它们被调用的其他时间而有所不同地工作,以某种方式跟踪它们的参数用过,......

例如,如果要将两个整数容器中的所有元素相加,可以执行以下操作:

struct
{
    int sum;
    void operator()(int element) { sum+=element; }
} functor;
functor.sum=0;
functor = std::for_each(your_first_container.begin(), your_first_container.end(), functor);
functor = std::for_each(your_second_container.begin(), your_second_container.end(), functor);
std::cout<<"The sum of all the elements is: "<<functor.sum<<std::endl;

  1. 实际上,正如R Samuel Klatchko在下面指出的那样,它们可以支持多个独立状态,每个状态对应一个仿真实例:
    稍微更准确的说法是仿函数可以支持多个独立状态(函数可以通过以下方式支持单个状态静态/全局,既不是线程安全的也不是可重入的。)
    Functors使您可以使用更复杂的状态,例如共享状态(静态字段)和私有状态(实例字段)。然而,很少使用这种进一步的灵活性。

答案 1 :(得分:8)

通常使用函数对象(仿函数)代替函数指针。函数指针存在编译器通常将它们作为原始指针传递的问题,这使得编译器很难在以后内联代码。而且它们更容易提供参数。

答案 2 :(得分:2)

函数对象的设计允许在STL上实现强大的抽象层,在这方面它们很棒。

但是,我更喜欢使用boost::bind并将函数绑定到STL算法 - 通常(虽然不是在对象具有状态的情况下)看起来更优雅溶液

std::for_each( callback.begin(), callback.end(), 
    boost::bind(&Callback::call(),_1) 
);

此外,另一个即将推出的替代方案是C ++ 0x中的lambda(例如从维基百科中无耻地被盗):

std::vector<int> someList;
int total = 0;
std::for_each(someList.begin(), someList.end(), [&total](int x) {
  total += x;
});
std::cout << total;

请注意,由于关闭,他们对没有状态的绑定有限制。

答案 3 :(得分:2)

函数对象是一个也是对象的函数,即它具有状态。正常功能通常没有状态。他们可以通过访问全局变量来模拟具有状态,但是然后在所有调用中共享状态。

答案 4 :(得分:2)

将函数封装为对象的想法可以追溯到Lisp和Smalltalk。编剧的C ++理念是吉姆·科普利恩1991年的书Advanced C++ Programming Styles and Idioms中的一章.STL用这个成语并进一步推广它。

答案 5 :(得分:1)

我不能说他们为什么会这样 - 可能只是因为他们可以!

你什么时候使用仿函数?考虑到一个仿函数只是将你通常放在一个循环中的代码移动到一个类的operator()中,它们与在while循环中调用一个函数没有多大区别......除了使用它们你允许编译器内联代码,你也可以传递一个预构造的对象,你用一些状态构造它。后一点使他们非常强大。

将排序算法与CRTs qsort调用进行比较。他们做同样的事情,只做不同的事情。

答案 6 :(得分:1)

This article深入了解函数对象,以及它如何使代码更强大,更清晰。