仿函数(functors)使用

来源:互联网 发布:windows 10 蓝牙 丢失 编辑:程序博客网 时间:2024/05/17 03:13

我们都知道C++有一个标准库STL,熟练使用STL可以提高我们开发的效率。可能很多人都熟悉诸如vector,list,map等容器,但是作为STL六大组件的仿函数则不太了解,或许有人说,这是个什么东西?学了有什么好处?

仿函数,它行为类似函数,可以作为算法的某种策略,帮助我们更好的使用算法。我们简单看一个例子:

//排序一组数据#include <iostream>#include <vector>#include <algorithm>#include <functional>using namespace std;void PrintV(const vector<int>& v){    int size = v.size();    for (int i = 0; i < size; ++i)    {        cout << v[i] << " ";    }    cout << endl;}int main(){    vector<int> v = { 3, 2, 1, 6, 5, 4 };    //默认升序 <    sort(v.begin(), v.end());    PrintV(v); // 1 2 3 4 5 6    //降序 >    sort(v.begin(), v.end(), greater<int>());    PrintV(v); // 6 5 4 3 2 1    //升序 <    sort(v.begin(), v.end(), less<int>());    PrintV(v); // 1 2 3 4 5 6    return 0;}

在上面的例子中,我们想对vector里面数据排序,升序和降序,我们不需要自己写,只需要调用sort,并根据要求传入仿函数以保证升序还是降序,是不是很方便呢?

当然排序这个算法不算难,但是在实际编程用STL,在绝大部分场合下无论是效率还是时间都远比我们自己写一个要快,更可况STL中实现的一个泛型算法,可以针对任意类型排序,而这样就需要我们了解仿函数。

什么是仿函数?所谓仿函数functor,又叫函数对象,它用起来就像函数一样。如果你对某个class进行operator()重载,他就是仿函数。

什么叫用起来像函数?比如:

template<class T>struct Plus{    T operator()(const T& a, const T& b)    {        return a + b;    }};int main(){    Plus<int> f;    cout << f(1, 2) << endl;}

在这里面,f看起来就像一个函数一样,实际上只是一个类对象调用operator()而已。它也可以这么写,结果是一样的。

cout << Plus<int>()(1, 2) << endl; //构造一个临时对象Plus<int>(),然后再调用operator()

经过上面的描述,我们知道要想使用仿函数,需要operator()重载,调用时候只需要生成对象x,再调用x()就可以完成我们所需的操作。

在前面,我们讲过STL设计是可以针对任意类型的,因此,我们自己定义的类型也可以被STL兼容。我们还是拿上面的sort为例子,在某些情况,我们可能一个元素有多个参数,但是要根据某个参数来排序,比如学生要根据成绩排名,学生的信息可能是这样的:

class Student{public:    Student(string n, int i, double s)        : name(n), id(i), score(s)    {}    double GetScore() const     {        return score;    }    string GetName() const    {        return name;    }    int GetID() const    {        return id;    }private:    string name;    int id;    double score;};bool Com(const Student& s1, const Student& s2) //升序策略{    return s1.GetScore() < s2.GetScore();}struct Com_D //降序策略{    bool operator()(const Student& s1, const Student& s2)    {        return s1.GetScore() < s2.GetScore();    }};void display(const Student& x){    cout << x.GetName() << " " << x.GetScore() << endl;}class Display{public:    void operator()(const Student &x)    {        cout << x.GetName() << " "  << x.GetScore() << endl;    }};int main(){    vector<Student> v;    v.push_back(Student("peter", 1, 60.9));    v.push_back(Student("andy", 2, 85.5));    v.push_back(Student("david", 3, 72.9));    v.push_back(Student("john", 4, 33.3));    v.push_back(Student("tom", 5, 92.5));    //按照成绩升序    sort(v.begin(), v.end(), Com); //函数指针    for_each(v.begin(), v.end(), display); //函数指针    cout << endl;    //按照成绩降序    sort(v.begin(), v.end(), Com_D());    for_each(v.begin(), v.end(), Display());    return 0;}

注意,函数指针也可以理解为一种仿函数,因此sort(v.begin(), v.end(), Com);中的Com就是一个函数指针,传入给sort,也许有人会问,既然函数指针也能完成这个需求,为什么还要这么烦设计出仿函数,这是因为函数指针不能满足STL对于抽象性的要求,它也无法与STL其他组件搭配,因而必须要有仿函数。

0 0