看到有个概念叫“函数对象”,搜了一下关于它的解释:


数对象(function 
object),又名仿函数(functor),是重载了operator()的一个类,其实在stl算法中有大量运用,c++标准预定义的如
less <>,greater <>,bind2nd <>等 
  为什么引入仿函数? 
  原因: 
  1.仿函数有具体型别,可用在模板参数,而函数不行 
  2.同类仿函数可有不同植,可代表不同状态,比函数灵活(须定义多个) 
  3.仿函数可能比普通函数快 
  ........可能还有,不过凭印象就这些了

  和普通函数相比,在不破坏接口的情况下,函数对象可以有自己的状态.

另外,

1 什么是函数对象

c++在模板方面使用很多的一个技术,写一个类,这个类有个成员函数,可以让类象函数一样运行。
主要用于模板函数中。

2 实现

类的成员函数,()可以让一个类运行起来象一个函数一样,如我们在排序的时候我们使用sort
可能sort是这样的sort(int, int)
我们自己可以写一个类,其中重载void operator()(int, int)来实现。

for_each(begin, end, func)
这个func如果是函数的话,会把value(*it)放在函数的参数位置上,如果是一个类在那个位置,将会调用运算符函数()来将参数传递进去。首先调用构造函数,构造函数初始化一个对象后,对象调用函数()来实现函数对象操作。

3 函数对象的优势

函数对象的功能于函数的功能是一样的,那为什么要使用默认构造函数。
1 函数对象是一个智能对象,他可以利用对象中的成员函数,和成员变量。
2 完全可以使用类的优势,可以使用类的重载特性,同样的一个类的名字,可以调用各种函数。

more exceptional c++The C++ Programming Language等书里有看到。

函数对象示例:

  1. // Negate.cpp
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. class Negate
  6. {
  7. public:
  8.        template<class T> T operator()(T t) const
  9.        {
  10.               return -t;
  11.        }
  12. };
  13. void Callback(int n, const Negate& neg)  // 传递一个函数对象
  14. {
  15.        n = neg(n);  // 调用重载的 () 操作 来对 n 进行 negate 操作
  16.        cout << n << endl;
  17. }
  18. int main(int argc, char* argv[])
  19. {
  20.        // 调用方式一
  21.        Callback(5, Negate());
  22.        // 调用方式二
  23.        Negate neg;
  24.        cout << neg(9.99999) << endl;      
  25.        cout << neg(__int32(39999999)) << endl;
  26.        getchar();
  27.        return 0;
  28. }

PS:

定义函数对象

时间:2001/02/07 15:22 作者:vckbase VC知识库


  尽管函数指针被广泛用于实现函数回调,但C++还提供了一个重要的实现回调函数的方法,那就是函数对象。函数对象(也称“算符”)是重载了“()”操作符的普通类对象。因此从语法上讲,函数对象与普通的函数行为类似。

用函数对象代替函数指针有几个优点,首先,因为对象可以在内部修改而不用改动外部接口,因此设计更灵活,更富有弹性。函数对象也具备有存储先前调用
结果的数据成员。在使用普通函数时需要将先前调用的结果存储在全程或者本地静态变量中,但是全程或者本地静态变量有某些我们不愿意看到的缺陷。

其次,在函数对象中编译器能实现内联调用,从而更进一步增强了性能。这在函数指针中几乎是不可能实现的。

下面举例说明如何定义和使用函数对象。首先,声明一个普通的类并重载“()”操作符:

class Negate

{

public:

int operator() (int n) { return -n;}

};

重载操作语句中,记住第一个圆括弧总是空的,因为它代表重载的操作符名;第二个圆括弧是参数列表。一般在重载操作符时,参数数量是固定的,而重载“()”操作符时有所不同,它可以有任意多个参数。

因为在Negate中内建的操作是一元的(只有一个操作数),重载的“()”操作符也只有一个参数。返回类型与参数类型相同-本例中为int。函数返回与参数符号相反的整数。

使用函数对象

我们现在定义一个叫Callback()的函数来测试函数对象。Callback()有两个参数:一个为int一个是对类Negate的引用。Callback()将函数对象neg作为一个普通的函数名:

#include

using std::cout;

void Callback(int n, Negate & neg)

{

int val = neg(n); //调用重载的操作符“()”

cout << val;

}

不要的代码中,注意neg是对象,而不是函数。编译器将语句

int val = neg(n);

转化为

int val = neg.operator()(n);

通常,函数对象不定义构造函数和析构函数。因此,在创建和销毁过程中就不会发生任何问题。前面曾提到过,编译器能内联重载的操作符代码,所以就避免了与函数调用相关的运行时问题。

为了完成上面个例子,我们用主函数main()实现Callback()的参数传递:

int main()

{

Callback(5, Negate() ); //输出 -5

}

本例传递整数5和一个临时Negate对象到Callback(),然后程序输出-5。

模板函数对象

从上面的例子中可以看出,其数据类型被限制在int,而通用性是函数对象的优势之一,如何创建具有通用性的函数对象呢?方法是使用模板,也就是将重载的操作符“()”定义为类成员模板,以便函数对象适用于任何数据类型:如double,_int64或char:

class GenericNegate

{

public:

template T operator() (T t) const {return -t;}

};

int main()

{

GenericNegate negate;

cout<< negate(5.3333); // double

cout<< negate(10000000000i64); // __int64

}

如果用普通的回调函数实现上述的灵活性是相当困难的。

标准库中函数对象

C++标准库定义了几个有用的函数对象,它们可以被放到STL算法中。例如,sort()算法以判断对象(predicate
object)作为其第三个参数。判断对象是一个返回Boolean型结果的模板化的函数对象。可以向sort()传递greater<>或
者less<>来强行实现排序的升序或降序:

#include // for greater<> and less<>

#include //for sort()

#include

using namespace std;

int main()

{

vector vi;

//..填充向量

sort(vi.begin(), vi.end(), greater() );//降序( descending )

sort(vi.begin(), vi.end(), less() ); //升序 ( ascending )

}