原文:STL Function objects
作者:Chris Losinger.
原文地址:http://www.codeproject.com/vcpp/stl/functor.asp
翻译:jans
这篇文章讨论了一个简单的STL函数对象,一个函数对象函数被称为算法,也就是说它们和标准C库函数相比,它们更为通用。STL算法通过重载operator()函数实现为模板类或模板函数。这些类用于创建函数对象,对容器中的数据进行各种各样的操作。函数对象可以维护自己的状态。这一点对于不仅仅是比大小的情形特别有用。
std::sort
就像C语言中古老的qsort函数,std::sort函数可以接受一个比较函数参数,这个函数在数组中两个对象进行比较时被调用。典型的比较函数如下:
bool compare_myObjects(const CMyObject &a, const CMyObject &b)
{
return a.x < b.x;
}
你可以对下面的对象数组进行排序:
// declare the vector
vector <CMyObject> myArray;
... initialize the vector
.
.
.
// sort it
std::sort(myArray.begin(), myArray.end(), compare_myObjects);
99%情况下,这种方式工作的都很好。
下面我们讨论其它1%的情况
如果你需要进行排序的不是基于一个数组中的两个对象,如果排序时对象间的比较还要访问其它一些非全局变量,或者是你要排序的数组基于另一个数组的内容? 当然用一些全局变量,你可做到这些,但是那样不是好的编程风格,函数对象,可以帮助你用面向对象的C++风格做到这些。
binary_function
binary_function是一个模板,可以允许你定义一个类,其行为像一个二元操作符,它接受两个参数,类型A,B返回类型C,它就像一个类,当用在函数中时,比如std::sort
也就是是一个函数。你可以在类中保存一些状态信息,用来比较或者作为二元操作符调用,就像上面的compare_myObjects函数
对基于另一个数组之上的数组的排序
举一个下面的例子,有两个数组:一个数组叫employee对象,另一个是整数数组,这个整数数组是employee对象数组中对象的索引数组,我们将对这个数组进行排序。假定我们无法直接对employee对象数组进行排序,比如因为某种原因我们不能破坏employee对象数组中对象元素的顺序。
首先,定义employee类:
class employee
{
public:
int m_salary;
string m_name;
};
其次,定义一个binary function
//这个类就是函数对象类
//定义对employee数组的引用
class employeecomp : public std::binary_function<int,int,bool>
{
// the vector reference
const vector<employee> &m_employees;
public:
// 构造时对employee数组引用
employeecomp( const vector<employee> & employees ) : m_employees(employees) {}
// 比较操作符. 将被std::sort引用,用来进行两个元素的比较,根据输入的值a,b返回比较结果
bool operator()(int a, int b) const
{
//输入的值是employees数组中元素的索引,然后进行比较的是根据索引得到的employe的m_salary变量
return (m_employees.at(a).m_salary) < (m_employees.at(b).m_salary);
}
};
使用一下我们定义的函数对象:
先初始化两个数组
//我们将要进行排序的索引数组
vector<int> indexVector;
// employee数组
vector<employee> employeeVector;
//初始化索引数组
for (int i=0; i < 4; i++)
{
indexVector.push_back(i);
}
//初始化employee数组,为其增加内容
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);
排序前我们看一下indexVector数组的内容:
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++;
}
所有排序要的东西都在这儿了,前两个参数就是我们要排序的数组的起点和终点,第三个参数就是所谓的断言函数. 这种情况下, 断言就是一个刚刚初始化的包含了employe数组的employeecomp对象. 对于每次比较std::sort需要先调用Pr(x,y), Pr是比较函数.比较函数就是 employeecomp对象的"()"操作符,x和y就是indexVector里面的两个元素.
std::sort(indexVector.begin(),
indexVector.end(),
employeecomp(employeeVector)); // employeecomp需要初始化其中employee数组
//排序后我们看一下indexVector数组的内容:
printf("After sorting/n");
i = 0;
for (it = indexVector.begin(); it != indexVector.end(); it++)
{
printf("indexVector[%d] = %d/n", i, (*it));
i++;
}
排序前索引数组内容为:
indexVector[0] = 0
indexVector[1] = 1
indexVector[2] = 2
indexVector[3] = 3
排序后:
indexVector[0] = 0
indexVector[1] = 3
indexVector[2] = 2
indexVector[3] = 1
你可以看到indexVector已经变了.但是发生了怎么样的改变呢?
indexVector数组中的值现在表示的是employeeVector数组的索引,按照salary递增排序. 但是 employeeVector数组并没改变。
这个是一个基本的关于函数操作符的例子,尽管如此,它在一些情形下仍然是一个非常有用的技术,因为你可以基于binary_function 创建一个全功能的类,无论其有多么复杂性(例如可以对一个函数对象的数组排序)而且也不仅仅限于std:sort函数中使用,还可用于STL中的其他算法。
感谢你的关注!