浅谈:函数指针、仿函数和函数适配…

一,仿函数是什么
前几天写了篇博客—— 浅谈函数指针,主要讲我对函数指针的理解和应用经验。今天,翻看了《C++Primer Plus》第16章“函数对象”这一节,发现C++中还有比函数指针更高层次的抽象——functor,中文名为“仿函数”“类函数”或“函数对象”。它的实际就是“重载了'operator()'的类”,并兼容函数指针。如下:
class Linear
{
private:
    double slope;
    double y0;
public:
    Linear(double sl_ = 1, double y_ = 0)
        : slope(sl_), y0(y_) {}
    double operator() (double x) { return y0 + slope * x; }
应用:
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);

这样,可以将类对象当函数一样使用,故称为仿函数。

二、为什么要用仿函数
STL的算法函数,可以接受一个自定义的仿函数,包括函数指针。它的原型是:
template
Function for_each(InputIterator first, InputIterator end, Functin f);
其中,Function是类型参数,(泛型)f可以传函数或函数指针或仿函数给它。
仿函数f将作用于容器中的各个元素,故它必须有一个参数或多个参数,此外它还可以有返回值。C++中根据仿函数的参数个数将它们分为一元和二元两类,同时又根据返回值是void或bool再进行分类。
问题来了。仿函数可以有多种类别,而STL某个特定算法函数,能接收的函数参数只能是其中的一种仿函数类别。如for_each只接受一元返回值为void的仿函数,而sort要接受二元返回值为bool的反函数。
这样就需要一种能够进行函数类型转换的solution,它就是仿函数。例如:
bool tooBig(int n) { return n > 100; }
list scores;
...
scores.remove_if(tooBig);
以上代码能够删除list中大于100的数,门限是“100”。但如果用户要指定门限,怎么办?修改tooBig函数?但是remove_if只接收一元的仿函数。
Solution:设计一个类,用类的成员变量来传递“门限”这个额外的信息。
template
class TooBig
{
private:
    T cutoff;
public:
    TooBig(const T & t) : cutoff(t) {}
    bool operator() (const T & v) { return v > cutoff; }
}

三、STL预定义仿函数
参考《C++Primer Plus》,列了一张表,对基本运算符都列了仿函数。此外还有常用的"sqrt""mean"“add”等。

四、函数适配器
STL使用binder1st和binder2nd类自动完成仿函数类型的转换。也可以根据这一思想自己实现。

五、自适应仿函数
使用模版实现





你可能感兴趣的:(浅谈:函数指针、仿函数和函数适配…)