什么是仿函数(函数对象)?为什么不直接用函数指针?
可以当函数使用的对象,一个类或结构体,重载圆括号操作符 "()",可以像函数一样被调用。仿函数对象可以当成参数传入函数中。
class/struct Obj{
operator()(args){...}
};
Obj obj;
//方法1
obj(args);
//方法2
Obj()(args);
为什么重载()运算符可以调用?C++的规定
STL(标准模板库)中,使用仿函数而不是简单的函数指针:
- **封装性:**仿函数可以封装状态,它们可以拥有数据成员。仿函数可以在多次调用之间保持一些内部状态。函数指针只能指向一个独立的函数,这个函数没有自己的状态。
- **灵活性:**由于仿函数是一个类,可以面向对象编程的特性。比如可以定义多个仿函数类来完成不同的任务,或者通过继承来扩展已有的仿函数类,这样可以更容易地组合和复用代码。
- STL中的许多组件(如容器、算法和迭代器)都是设计来协同工作的。仿函数可以更好地融入这种设计模式,尤其是当涉及到适配器(adapters)和其他高级特性时。仿函数可以被设计成STL组件的一部分,使得它们可以轻松地与其他STL组件交互。(需要理解)
比较大小的仿函数std::greater和std::less
cpp
template<typename _Tp>
struct greater{
bool operator()(const _Tp& __x, const _Tp& __y) const
{ return __x > __y; }
};
template<typename _Tp>
struct less{
bool operator()(const _Tp& __x, const _Tp& __y) const
{return __x < __y;}
};
cpp
greater<int>gt;
cout<<gt(2,3); //0
STL 仿函数的分类,若以操作数(operand)的个数划分,可分为一元和二元仿函数,若以功能划分,可分为算术运算(Arithmetic)、关系运算(Rational)、逻辑运算(Logical)三大类。任何应用程序欲使用 STL 内建的仿函数,都必须包含 <functional> 头文件,SGI 则将它们实际定义于<stl_function.h>文件中。
可配接(Adaptable)的关键
仿函数的相应型别主要用来表现函数参数型别和传回值型别。为了方便起见,<stl_function.h>定义了两个 classes,分别代表一元仿函数和二元仿函数(STL不支持三元仿函数),其中没有任何数据成员和成员函数只有一些型别定义。
任何仿函数,只要选择继承其中一个 class,就拥有那些相应型别,也就自动拥有了配接能力。
一元仿函数:unary_function
unary_function用来呈现一元函数的参数型别和回返值型别。其定义非常简单:
cpp
// STL规定,每一个 Adaptable Unary Function 都应该继承此类别。
template <class Arg,class Result>
struct unary_function {
typedef Arg argument_type; //表示仿函数的参数类型.
typedef Result result_type;//表示仿函数的返回类型.
}
cpp
template <classT>structnegate : public unary_function<T, T> {
T operator()(const T& x)const{ return -x; }
};
negate
继承了unary_function<T, T>
,说明它的参数类型和返回类型都是 T
。operator()
是重载的函数调用运算符,使得这个结构体可以像函数一样被调用。它接受一个参数并返回其负值。
仿函数适配器unary_negate
cpp
template <class Predicate>
class unary_negate {
public:
bool operator()(const typename Predicate::argument_type& x) const {
// 逻辑负值操作
}
};
通过组合已有的仿函数来创建新的行为。在这种情况下,unary_negate
将一个仿函数的逻辑输出取反。这种方式可以避免重复编写逻辑负值的代码,而是通过组合来实现新功能。
二元仿函数:binary_function
cpp
template <class Arg1, class Arg2, class Result>
struct binary_function {
typedef Arg1 first_argument_type;//二元仿函数的第一个参数类型
typedef Arg2 second_argument_type;//二元仿函数的第二个参数类型
typedef Result result_type;//二元仿函数的返回值类型
};
cpp
template<class T>
struct plus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x + y; }
};
plus
继承了binary_function<T, T, T>
,表示两个参数和返回值都是类型 T
。operator()
是重载的函数调用运算符,使得 plus
仿函数可以像普通函数一样使用,它接受两个参数并返回它们的和。
仿函数适配器 binder1st
cpp
template <class Operation>
class binder1st {
protected:
Operation op;
typename Operation::first_argument_type value;
public:
typename Operation::result_type
operator()(const typename Operation::second_argument_type& x) const {
return op(value, x);
}
};
binder1st
适配器通过将二元仿函数的第一个参数绑定为固定值,将其转换为一元仿函数。
算术类仿函数
STL 内建的"算术类仿函数",支持加法、减法、乘法、除法、模数(余数,modulus)和否定(negation)运算。除了"否定"运算为一元运算,其它都是二元运算。
加法(plus<T>),减法(minus<T>),乘法(multiplies<T>),除法(divides<T>),模取(modulus<T>),否定(negate<T>)
cpp
template <class T>
struct plus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x + y; }
};
template <class T>
struct minus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x - y; }
};
template <class T>
struct multiplies : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x * y; }
};
template <class T>
struct divides : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x / y; }
};
template <class T>
struct modulus : public binary_function<T, T, T> {
T operator()(const T& x, const T& y) const { return x % y; }
};
template <class T>
struct negate : public unary_function<T, T> {
T operator()(const T& x) const { return -x; }
};
关系运算类仿函数
STL 内建的"关系运算类仿函数"支持了等于、不等于、大于、大于等于、小于、小于等于六种运算。每一个都是二元运算。
等于(equal_to<T>),不等于(not_equal_to<T>),大于(greater<T>),大于或等于(greater_equal<T>),小于less<T>,小于或等于less_equal<T>。
cpp
template <class T>
struct equal_to : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x == y; }
};
template <class T>
struct not_equal_to : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x != y; }
};
template <class T>
struct greater : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x > y; }
};
template <class T>
struct less : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x < y; }
};
template <class T>
struct greater_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x >= y; }
};
template <class T>
struct less_equal : public binary_function<T, T, bool> {
bool operator()(const T& x, const T& y) const { return x <= y; }
};
证同(identity)、选择(select)、投射(project)
identity****仿函数
cpp
struct identity : public unary_function<T, T> {
const T& operator()(const T& x) const { return x; }
};
identity
仿函数直接返回其输入参数,不做任何修改。
select1st****仿函数
cpp
template <class Pair>
struct select1st : public unary_function<Pair, typename Pair::first_type> {
const typename Pair::first_type& operator()(const Pair& x) const {
return x.first;
}
};
接受一个 pair
,并返回其第一个元素(first)。
select2nd****仿函数
cpp
template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type> {
const typename Pair::second_type& operator()(const Pair& x) const {
return x.second;
}
};
project1st****仿函数
cpp
template <class Arg1, class Arg2>
struct project1st : public binary_function<Arg1, Arg2, Arg1> {
Arg1 operator()(const Arg1& x, const Arg2&) const { return x; }
};
接受两个参数,只返回第一个参数,忽略第二个参数。
project2nd****仿函数
cpp
template <class Pair>
struct select2nd : public unary_function<Pair, typename Pair::second_type> {
const typename Pair::second_type& operator()(const Pair& x) const {
return x.second;
}
};
接受两个参数,只返回第二个参数,忽略第一个参数。
这些仿函数在泛型编程中提供了抽象化和间接性。