1、函数对象
答:在《C++ Primer Plus》里面,函数对象是可以以函数方式与()结合使用的任意对象。这包括函数名、指向函数的指针和重载了“operator()”操作符的类对象。(C++11后更多的是使用重载“operator()”这种方式来使用函数对象),例如:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class FuncObject{
public:
FuncObject(int n = 0) : num(n), count(1){}
bool operator()(int) {
return count++ == num;
}
int GetCount(){
return count;
}
private:
int count;
int num;
};
int main(){
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> vec(a, a + 10);
FuncObject test(3);
vector<int>::iterator itr = find_if(vec.begin(),vec.end(), test);
cout << "3rd:" << *itr << endl;
cout << "State:" << test.GetCount() << endl;
}
2、谓词
答:在《C++ Primer》里面,谓词是一个可调用的表达式,其返回结果是一个能作为判断条件的值。(也有通俗的叫法是返回bool类型的仿函数称为谓词)
标准库使用的算法包括两种谓词:一元谓词(只接受一个参数)和二元谓词(只接受两个参数)。
例如下面是一个二元谓词:
bool isShort(const string &s1, const string &s2)
{
return s1<s2;
}
先来看看sort的原型:
template <class RandomAccessIterator>
void sort ( RandomAccessIterator first, RandomAccessIterator last );
template <class RandomAccessIterator, class Compare>
void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
可见第二个版本是可以指定第三个参数,这里我们使用一个二元谓词:
vector<string> vecStr={"12432", "sadf", "hjjhh"};
sort(vecStr.begin(), vecStr.end(), isShort);
当然我们的谓词也可以这样写:
class isShorter
{
public:
bool operator()(const string &s1, const string &s2)
{
-
return s1<s2;
}
};
调用就是这样:
sort(vecStr.begin(), vecStr.end(), isShorter());
注意:使用函数对象(重载了operator()的类对象,这里和叫它谓词还是函数对象就没有区别了)时要跟一个"()"来调用该操作符,而函数指针不用“()”,也就是说应该是存在从函数指针到函数对象的一个转换。
总结:我们使用的find_if第三个参数接收是一个函数对象,sort的第三个参数是接收二元谓词的一个版本,可发现一些共同点:
(1)谓词属于函数对象的一种,它是函数对象的一个分支,它们存在转换关系。
(2)不管是函数指针还是类对象,"()"得到的参数都是直接从算法遍历中获取来的,故形参类型需要和遍历的元素类型是一致的。如果有其它更严格的比较规则,可以使用重载operator()的类对象,比如需要判断遍历的元素是否大于某个传入的值,则可以用类对象的构造函数来保存到成员中,然后后面在重载的operator()函数中使用该值即可。
C++很多标准库算法都使用的是谓词,当然谓词有一些局限性(比如只接受一元和二元参数),很多时候我们会用重载operator()的类对象来操作。