65.9K
CodeProject 正在变化。 阅读更多。
Home

STL 函数对象

2001 年 9 月 25 日

3分钟阅读

viewsIcon

162207

downloadIcon

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),其中 Pr 是比较函数。在本例中,比较函数是 employeecomp 对象的“()”运算符;xy 是来自 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 算法中使用它。

负责任地享受。

© . All rights reserved.