大年三十头一天,过了初二就初三,初一十五半个月,六月三十整半年。
1. 为什么要有仿函数
函数已经非常努力了,我们为什么还要这样要求它!
有时候会遇到这样一些情况:我们想要一个函数然后把它的地址传给另一个函数(这样的场景非常多,比如说sort(a, a + n, cmp)这样的)。突然间你想到一件事情,发现自己应该给函数多传一个参数的(比如说类似于阈值一样的东西,可能是一个固定的值),此时如果修改函数签名,那么可能代码很多地方都要修改;如果修改函数的代码,把这个参数固定死,显得比较呆,也不方便变通;如果定义一个全局变量保存,需要时刻警惕有一个全局变量。所以仿函数应运而生(好吧上面几个场景好像没有仿函数其实也没什么大不了的)。
仿函数就是一个struct或者是class,它重载了operator()。这样的话你声明一个这样的变量,它其实用起来和一个函数就是一样的。这个东西的好处在于,仿函数本身其实是一个结构体或者是类的对象,所以它可以有很多成员变量,或者是成员函数。同时它可以重载好几个operator(),一个变量可以给很多人用;而且它在构造函数里可以指定函数的参数,这样代码复用性会比较好一些。、、
同时仿函数可以继承自父类,让它的灵活性大大增加。最后一点,也是我认为比较关键的一点是,传入一个类似函数一样的变量,比传入一个函数指针要安全很多。
2. 实际应用
实际上在 STL 中就有大量的仿函数,我们来看:
// stl_queue.htemplate<typename _Tp, typename _Sequence = vector<_Tp>,typename _Compare = less<typename _Sequence::value_type> >class priority_queue{// ...}template<typename _Tp>struct less : public binary_function<_Tp, _Tp, bool>{_GLIBCXX14_CONSTEXPRbooloperator()(const _Tp& __x, const _Tp& __y) const{ return __x < __y; }};
在这个例子中我们看到,优先队列的模板会要求我们传入三个东西:优先队列里装的东西的类型、容器选择什么,以及自定义比较函数。后两个我们都有缺省值,而比较函数的缺省值是一个`less`,实际上我们看到它其实就是一个结构体仿函数。所以我们自定义优先队列的比较的时候就可以自己实现一个结构体,里面重载一个括号运算符即可。
