函数对象
也叫做 函数符 (functor)。函数符是可以以函数方式与()结合使用的任意对象。这包括函数名、指向函数的指针和重载了()操作符的类对象(即定义了函数operator()()的类)。
例如,这样定义一个类:
class Linear
{ private:
double slope,y0;
public:
Linear (double _sl = 1, double _y = 0):slope(_s1),y0(_y) {}
double operator() (double x) {return y0 + slope * x;}
};
重载的()操作符将使得能够像函数那样使用Linear对象:
Linear f1;
linear f2 (2.5, 10.0);
double y1 = f1 (12.5); // right hand side is f1.operator()(12.5)
double y2 = f2 (0.4);
其中y1将使用表达式0 + 1 * 12.5来计算,y2将使用表达式10.0 + 2.5 * 0.4来计算。
举例说明函数符调用
函数for_each(),它将指定的函数用于区间中的每个成员:
for_each(books.begin(), books.end(), ShowReview);
通常,第3个参数可以是常规函数,也可以是函数符。如果把它声明为函数指针,则函数指针指定了参数类型。但由于容器可以包含任意类型,而无法预先知道将使用何种参数类型。所以STL通过使用模板来解决这个问题。
for_each的原型:
template<class InputIterator, class Function>
Function for_each(InputIterator first,InputIterator last, Function f);
假设ShowReview()的原型如下:
void ShowReview (const Review &);
那么,标识符ShowReview的类型将为 void (*) (const Review &),这也是赋给模板参数Function的类型。对于不同的函数调用,Function参数都可以表示具有重载的()操作符的类类型。最终,for_each()代码将具有一个使用f(...)的表达式。
在上面范例中,f是指向函数的指针,而f(...)调用该函数。如果最后的for_each()参数是一个对象,则f(...)将是调用重载的()操作符的对象。
函数符概念
生成器(generator),是不用参数就可以调用的函数符。
一元函数(unary function),是用一个参数可以调用的函数符。
二元函数(binary function),是用两个参数可以调用的函数符。
(例如,提供给for_each()的函数符应当是一元函数,因为它每次用于一个容器元素。)
返回bool值的一元函数是 断言 (predicate)。
返回bool值的二元函数是 二元断言 (binary predicate)。
list模板有一个将断言作为参数的remove_if()成员,该函数将断言应用于区间中的每个元素,如果断言返回true,则删除这些元素。
例如,下面的代码删除链表scores中所有大于100的元素:
bool tooBig(int n) { return n > 100; }
list<int> scores;
...
scores.remove_if(tooBig);
现在假设又要删除另一个链表中所有大于200的值。就必须重新设计一个断言。如果能将取舍值作为第二个参数传递给tooBig(),则可以使用不同的值调用该函数,但断言又只能有一个参数。不过,如果设计一个tooBig类,则可以使用类成员而不是函数参数,来传递额外的信息:
template<class T>
class tooBig
{ private:
T cutoff;
public:
tooBig (const T & t): cutoff(t) {}
bool operator() (const T & v) { return v > cutoff; }
};
这里,一个值(V)作为函数参数传递,而第二个参数(cutoff)是由类构造函数设置的。有了该定义后,就可以将不同的tooBig对象初始化为不同的取舍值,供调用remove_if()时使用:
scores.remove_if(tooBig<int>(200));
函数符(tooBig<int>(200))是一个匿名对象,它是由构造函数调用创建的。