C++中仿函数/函数对象,函数指针的用法

来源:互联网 发布:java界面编程教程 编辑:程序博客网 时间:2024/06/07 10:29

研究这个起因是这样的,就是今天在用priority_queue的时候,需要自定义比较函数,但是此时又不能修改需要比较的类的内容(即不能用重载<的方法),所以只能写在外面,但是发现这样并不能编译通过。报的错叫cmp(我写的那个比较函数)不是类型名。后来查了下资料发现,这个需要用比较类去完成,比较类需要重载()方法,所以这个事情就非常引起我的好奇,想要知道一下,为什么sort这样的函数就可以直接用函数名,而priority_queue就不行呢


基本概念

首先先要了解几个概念:函数对象/仿函数,函数指针,Lambda表达式

函数对象/仿函数

函数对象(function object)又叫仿函数(functor),就是重载了调用运算符()的类,所生成的对象,就叫做函数对象/仿函数。因为重载了()之后,我们就能像函数一样去使用这个类,同时类里面又可以储存一些信息,所以要比普通的函数更加灵活。
就像,下面的就是一个比较类:

class comp_class {public:    bool operator()(const B& a,const B& b) {        return a.a < b.a;    }};

函数指针

首先,函数指针也是一个函数对象,因为指针在C++中都是对象。

lambda表达式

lambda表达式的用法,我单独放偏博客来讲吧,这个坑先留着。这里就记住lambda也是一个函数对象就行了。


STL函数和STL容器

开头说到的sort就是STL函数(STL function),而priority_queue就是STL容器(STL containers)。
跟priority_queue类似的带着比较函数的容器还有set和map。记住STL容器中<>里面传入的一定是类型名称,不能是具体的实例。


程序例子

回到我们最开始的问题上,以set和sort为例

class B {public:    int a;    int b;    B(int _a,int _b):a(_a), b(_b) {};};class comp_class {public:    bool operator()(const B& a,const B& b) {        return a.a < b.a;    }};const bool comp_function(const B& a,const B &b) {    return a.a < b.a;}

然后以下是正确用法的有
对于set类

//传入比较类的set<B, comp_class> A_set;set<B, comp_class> A_set(comp_class ());//传入函数指针的set<B, const bool(*)(const B& a, const B &b)> A_set(comp_function);//记住参数一定要严格匹配,包括const//还可以这么写,简化声明,set<B, decltype(comp_function)*> A_set(comp_function);

注意此时一定要写*,因为用decltype来获得一个函数指针类型时,其只返回函数类型,而非指针类型,所以这个地方要显示的加上 * 表明这里是函数指针.

对于sort函数的传入

//传入比较类的sort(A_vector.begin(), A_vector.end()comp_class());    //注意后面的括号一定不能省略//传入函数指针的sort(A_vector.begin(), A_vector.end(),comp_function);

结论

所以开头中提到的问题,这里其实就已经非常明白了,我在查资料的时候,一直就坑在了这个地方,后来恍然大悟.
其实对于sort和set需要传进去的东西都是一致的.
只不过set中间需要定义的是类别模板而不是具体的比较函数,
所以其实set里面传入函数也是可以的,只不过在<>中需要写的不是具体函数名,而是这个函数指针的类型,然后用那个具体的函数来初始化set.就像我上面写的那样.
而对于sort来说,因为其本身就是一个函数了,所以传进去具体的比较函数实例就可以.
同理,如果再sort中传入的是类型也是不可以的,所以需要传入一个具体的实例,就像上面的那个sort必须要加()来给它实例化

1 0