为何引入函数对象
即在函数中调用所需类对象的函数,使程序结构同时显得非常简洁 。
函数对象是重载了operator()的类的一个实例,operator()是函数调用运算符。标准C++库根据operator()参数个数为0个,1个,2个加以划分的。
主要有以下3种类型:
- 发生器:一种没有参数且返回一个任意类型值的函数对象,例如随机数发生器。
- 一元函数:一种只有一个任意类型的参数,且返回一个可能不同类型值的函数对象。
- 二元函数:一种有两个任意类型的参数,且返回一个任意类型值的函数对象。
- 一元判定函数:返回bool型值的一元函数
- 二元判定函数: 返回bool型值的二元函数
class CSum
{
private:
int sum;
public:
CSum(){sum = 0;}
void operator()(int n)
{
sum += n;
}
int GetSum(){return sum;}
};
int main()
{
vector<int> v ;
for(int i=1; i<=100; i++)
{
v.push_back(i);
}
CSum sObj = for_each(v.begin(), v.end(), CSum());
printf("sum=%d\n", sObj.GetSum());
}
必须重载operator()函数:这是实现函数对象功能最重要的环节,不能随便写,因此6.1.1节中CSum类中的f(int)函数修改为operator()(int), 而函数体的内容不变。
函数对象调用方式:直接采用构造函数调用,如本例中for_each(v.begin(), v.end(), CSum())中的第3个参数CSum(), 也就是说:对本例而言,STL知道CSum()对应着CSum类中重载的operator()函数,具体有几个参数呢,由于for_each函数一次只能迭代出一个整形数,所以STL知道每迭代一次整形数,都要执行一次CSum中的operator()(int)函数。
CSum sObj是用来接收for_each迭代函数对象的最终结果值的。
一元函数
STL中一元函数基类是一个模板类,原形如下:
template<class _A, class _R>
struct unary_function {
typedef _A argument_type;
typedef _R result_type;
};
它有两个模板参数,_A是输入参数,_R是返回类型,且此两个参数的类型是任意的,因此,它的动态特性非常强。
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
template<typename _inPara, typename _outPara>
class CSum : public unary_function<_inPara, _outPara>
{
public:
_outPara sum;
CSum(){sum = 0;}
void operator()(_inPara n)
{
sum += n;
}
_outPara GetSum(){return sum;}
};
int main()
{
vector<int> v ;
for(int i=1; i<=100; i++)
{
v.push_back(i);
}
CSum<int,int> sObj=for_each(v.begin(), v.end(), CSum<int, int>());
cout << "sum(int)=" << sObj.GetSum() << endl;
vector<float> v2 ;
float f = 1.3f;
for(int i=1; i<=99; i++)
{
v2.push_back(f);
f += 1.0f;
}
CSum<float,float> sObj2=for_each(v2.begin(), v2.end(), CSum<float, float>());
cout << "sum(float)=" << sObj2.GetSum() << endl;
}
主要理解以下几点。
(1)应用STL模板一元函数必须从unary_function基类派生。例如本例中的CSum类。
(2)加深对一元函数模板类模板参数的理解。例如本例中的_inPara表示的是operator()函数的参数类型,所以写作void operator()(_inPara n),_outPara表示的是返回值的类型,因此返回值变量sum应定义成_outPara类型。由于此两个参数在本例中都是动态传进去的,因此在类定义的前面要加上template<class _inPara, class _outPara>。
(3)对调用模板函数对象方式的理解。例如本例中 CSum<int,int> sObj=for_each(v.begin(), v.end(), CSum<int, int>())表明是对整形向量元素求和,CSum<int,int>表明CSum是一个模板类,两个动态参数都是整形数;CSum<float,float> sObj2=for_each(v2.begin(), v2.end(), CSum<float, float>())表明是对浮点向量元素求和,两个动态参数都是浮点型。可以看出对整形向量求和、浮点向量求和都是由CSum函数对象类完成的,当然也可用CSum求其它数据类型的和,从中可以体会出STL中一元函数模板类功能的强大。
二元函数
STL中二元函数基类是一个模板类,原形如下所示。
template<class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;
typedef Arg2 second_argument_type;
typedef Result result_type;
};
它有三个模板参数,Arg1、Arg2是输入参数,Result是返回类型,且此三个参数的类型是任意的,因此,它的动态特性非常强。
利用二元函数使学生成绩升序排列。
class Student
{
public:
string name;
int grade;
public:
Student(string name, int grade)
{
this->name = name;
this->grade