STL 函数对象






4.85/5 (10投票s)
2001 年 9 月 25 日
3分钟阅读

162207

784
在 std::sort 中使用 STL 函数对象。
引言
本文介绍了一个简单的 STL 函数对象。函数对象是一种创建可以保持状态的函数的方法。这在排序情况下特别有用,在这种情况下,简单的“小于”或“大于”比较是行不通的。
std::sort
与 C 语言古老的 qsort
函数类似,STL 的 std::sort
函数可以接受一个比较函数作为其参数之一。当排序函数需要比较数组中的两个值时,会调用此比较函数。一个典型的 STL 比较函数是
bool compare_myObjects(const CMyObject &a, const CMyObject &b) { return a.x < b.x; }
你可以使用这个函数来排序 CMyObjects
的向量(数组),像这样
// declare the vector vector <CMyObject> myArray; ... initialize the vector . . . // sort it std::sort(myArray.begin(), myArray.end(), compare_myObjects);
这在您可能遇到的 99% 的情况下都适用。
剩下的 1%
如果需要根据两个对象中都不包含的信息对数组进行排序,该怎么办?例如,比较需要访问一些其他的非全局变量;或者,如果想要根据另一个数组的内容对一个数组进行排序,该怎么办?当然,可以使用全局变量来做到这一点,但这并不好。当然,函数对象可以帮助您以一种良好的 OO/C++ 的方式做到这一点。
binary_function
binary_function
是一个模板,实际上,它允许您定义一个可以充当二元运算符的类——它接受 A 和 B 类型的两个输入,并返回 C 类型的单个输出。它充当一个类,但当在诸如 std::sort
之类的函数中使用时,它也充当一个函数。因此,您可以将内容存储在类中,并使用它来执行比较(或者实际上是任何二元运算),就像上面的 compare_myObjects
函数一样。
基于另一个数组对一个数组进行排序
对于下面的示例,我们有两个 vector
:一个是 employee
对象数组;另一个是整数数组。整数数组是第一个数组的索引数组,我们将根据 employee
数组中的对象对这些索引进行排序。假设有一些很好的理由说明我们不能直接对 employee
数组本身进行排序,比如它已经被排序过了,我们不想破坏它当前的顺序。
首先,一个员工
class employee { public: int m_salary; string m_name; };
其次,一个二元函数
// this is our function object class. // it holds a reference to a vector of employees. class employeecomp : public std::binary_function<int,int,bool> { // the vector reference const vector<employee> &m_employees; public: // constructor which takes a reference to a vector of employees employeecomp( const vector<employee> & employees ) : m_employees(employees) {} // comparison operator. this will be called by std::sort with two // integers. we'll perform a comparison operation on the inputs and // return the result of the comparison. bool operator()(int a, int b) const { // a typical comparison operator compares the two input parameters. // this one uses the two input parameters as indexes into the m_employees vector. return (m_employees.at(a).m_salary) < (m_employees.at(b).m_salary); } };
使用这些东西
首先,初始化这两个向量
// index array. this is what we'll sort vector<int> indexVector; // employees. this is what the sorting of indexVector is based on vector<employee> employeeVector; // initialize indexVector for (int i=0; i < 4; i++) { indexVector.push_back(i); } // initialize some employees employee h; h.m_salary = 0; h.m_name = "fred"; employeeVector.push_back(h); h.m_salary = 99; h.m_name = "ethel"; employeeVector.push_back(h); h.m_salary = 32; h.m_name = "ricky"; employeeVector.push_back(h); h.m_salary = 23; h.m_name = "lucy"; employeeVector.push_back(h);
预排序
// show the index vector before sorting printf("Before sorting\n"); vector<int>::iterator it; i = 0; for (it = indexVector.begin(); it != indexVector.end(); it++) { printf("indexVector[%d] = %d\n", i, (*it)); i++; }
排序!这就是所有内容汇集的地方。前两个参数是我们要排序的 vector
的开始和结束位置。第三个参数被称为“谓词”。在本例中,谓词是一个 employeecomp
对象,我们使用 employee 向量对其进行初始化。对于 std::sort
需要执行的每次比较,它将调用 Pr(x,y)
,其中 P
r 是比较函数。在本例中,比较函数是 employeecomp
对象的“()”运算符;x
和 y
是来自 indexVector
的两个项目。
std::sort(indexVector.begin(),
indexVector.end(),
employeecomp(employeeVector)); // initialize our functor
排序后
// show the index vector after sorting printf("After sorting\n"); i = 0; for (it = indexVector.begin(); it != indexVector.end(); it++) { printf("indexVector[%d] = %d\n", i, (*it)); i++; }
...结果
Before sorting indexVector[0] = 0 indexVector[1] = 1 indexVector[2] = 2 indexVector[3] = 3 After sorting indexVector[0] = 0 indexVector[1] = 3 indexVector[2] = 2 indexVector[3] = 1
正如您所看到的,indexVector
已经改变了。但它改变成了什么? indexVector
中的值现在显示了 employeeVector
中项目的索引,按工资递增排序。而且,虽然我没有在这里展示,但 employeeVector
根本没有被修改。
这是一个函数运算符可以做的非常基本的示例。不过,这是一种在某些情况下可能非常有用的技术。因为 binary_function
模板创建了一个功能齐全的类,所以您可以向其中添加的复杂性没有限制(例如,对函数对象的 vector
进行排序)。此外,此技术不限于 std::sort
;您可以在许多 STL 算法中使用它。
负责任地享受。