1、与智能指针一样,函数对象也是一个普通的类对象。
智能指针类型重载->和*(可能还有->*)操作符,来模仿指针的行为;
而函数对象类型则重载函数调用操作符( ),来创建类似于函数指针的东西。
函数对象只是常规的类对象,但是可以采用标准的函数调用语法来调用它的operator()成员。
(此成员可能具有多个重载版本)。
Fib fib;
//....
cout<<"next two in series: "<<fib( )<<' '<<fib( )<<endl;
fib( )语法被编译器识别为对fib对象的operator( )成员函数的调用,这和fib.operator( )等价。
2、一个积分函数可以对low和high之间的值反复调用一个函数,来近似计算曲线所包围的面积,这是通过计算矩形面积的总和而实现的。
typedef double ( *F) ( douoble);
double integrate ( F f, double low, double high ) {
const int numsteps = 8;
double step = (high - low) / numsteps;
double area = 0.0;
while( low<high ) {
area += f( low ) * step;
low += step;
}
return area;
}
在这个版本中,传递一个函数指针来执行所期望的积分操作:
double aFunc( double x) { ..... }
//......
double area = integrate ( aFunc, 0.0, 2.71828 );
这种方法有效但不灵活,因为它使用一个函数指针来指示待整合的函数,但是它不能处理需要状态的函数或指向成员函数的指针。
一个替代的方式是创建一个函数对象层次结构。该层次结构的基类是一个简单接口类,只声明了一个纯虚operator( )。
class Func {
public:
virtual ~Func( );
virtual double operator ( ) (double) = 0;
};
double integrate( Func &f, double low, double high);
现在integrate能够与任何类型的Func函数对象进行整合。
integrate函数体不需要进行任何修改(当然重新编译一遍是免不了的),因为我们使用与调用函数指针相同的语法来调用一个函数对象。
例如,可以派生出一个能处理非成员函数的Func类型:
class NMFunc : public Func {
public:
NMFunc ( double (*f) (double ) ) : f_(f) { }
double operator( ) ( double d) { return f_(d); }
private:
double (*f_) (double);
};
这就允许整合所有最初版本的函数:
double aFunc( double x) { ... }
//.....
NMFunc g( aFunc );
double area = integrate( g, 0.0, 2.78128);