C++ 函数对象
1、考虑下面的需求,从集合中找到一个与当前Student相等的学生,如下:
int main(int argc, char* argv[])
{
Student s1(20,"Andy");
Student s2(23,"Bill");
Student s3(28,"Caroline");
Student s4(27,"David");
Student s5(21,"Eric");
vector<Student> stuVec;
stuVec.push_back(s1);
stuVec.push_back(s2);
stuVec.push_back(s3);
stuVec.push_back(s4);
stuVec.push_back(s5);
Student target(23,"Bill");
vector<Student>::iterator iter = find(stuVec.begin(),stuVec.end(),target);
return 0;
}
注意:调用find方法,Student要重载成员操作符==,或者重载普通操作符==,因为find使用==比较两个对象是否相等。
2、需求变更,找出一个年龄比target大的学生,怎么办?
使用函数对象,函数对象有一个成员_stu,使用target初始化_stu,重载(),比较target与序列中的每个对象
class Finder
{
public:
Finder(const Student& stu):_stu(stu)
{
}
bool operator()(const Student& rhs)
{
if(rhs._Age>_stu._Age)
{
return true;
}
return false;
}
private:
Student _stu;
};
iter = find_if(stuVec.begin(),stuVec.end(),Finder(target));
注:假如对于teacher的集合,也要同样的需求,找出一个年龄比target大的教师,可以将Finder修改成模板类。
3、有没有其他的办法呢?
使用greater<Student>可以比较Student的大小,一个是变量,一个是参照物,而find_if的第三个参数,隐式接口是 Pred(*First),只接受一个参数。
使用bind2nd 对greater<Student>和参照物封装,对外暴露接口接受一个参数,对内调用greater(参数,参照物),greater使用>比较大小,对Student进行>操作符过载。
bool operator>(const Student& lhs,const Student& rhs)
{
return lhs._Age > rhs._Age;
}
iter = find_if(stuVec.begin(),stuVec.end(),bind2nd(greater<Student>(),target));
4、其他办法呢?
不过载操作符,偏特化一个greater,用于比较age大小。如下:
template <>
struct greater<Student>: public binary_function<Student, Student, bool>
{
bool operator()(const Student& _Left, const Student& _Right) const
{
return (_Left._Age > _Right._Age);
}
};
iter = find_if(stuVec.begin(),stuVec.end(),bind2nd(greater<Student>(),target));
5、因为偏特化只有一个,能不能自己写一个类似greater的方法对象呢,并且是可以使用bind2nd适配的。
注意:为了可适配,需要继承 public binary_function<Student, Student, bool>
struct StudentNameCompare: public binary_function<Student, Student, bool>
{
bool operator()(const Student& _Left, const Student& _Right) const
{
return (_Left._Age > _Right._Age);
}
};
iter = find_if(stuVec.begin(),stuVec.end(),bind2nd(StudentNameCompare(),target));
当然也可以使用模板,如下:
template <typename T>
struct StudentNameCompare: public binary_function<T, T, bool>
{
bool operator()(const T& _Left, const T& _Right) const
{
return (_Left._Age > _Right._Age);
}
};
iter = find_if(stuVec.begin(),stuVec.end(),bind2nd(StudentNameCompare<Student>(),target));
6、现在分析2的方法和5的方法,最终的接口都要满足 Pred(*First),只接受一个参数。二者的处理策略不同。 在2中,函数对象,只接受一个参数,但是有一个字段,这个字段用于保存参照物。在5中,函数对象接受两个参数,继承binary_function,使之可适配,然后使用bind2nd 将函数对象和参照物封装起来,对外暴露接口只接受一个参数。
7、考虑下面的需求,找出一个年龄比target小的学生,对于5,只需要使用not1再次适配一下即可,如下:
iter = find_if(stuVec.begin(),stuVec.end(),not1(bind2nd(StudentNameCompare<Student>(),target)));
但是对于2,不行。因为2不是可适配的,要让2是可适配的,需要继承 public unary_function<Student,bool>,如下:
class Finder:public unary_function<Student,bool>
{
public:
Finder(const Student& stu):_stu(stu)
{
}
bool operator()(const Student& rhs) const
{
if(rhs._Age>_stu._Age)
{
return true;
}
return false;
}
private:
Student _stu;
};
当然,也可以使用模板。