STL之仿函数

本文详细介绍了C++中的仿函数概念及其应用。包括了预定义的一元和二元仿函数,如算术类、关系类及逻辑类仿函数,并提供了自制仿函数的实例。

一、概述

仿函数是早期命名,C++标准后采用新名称函数对象。函数对象即指具有函数特质的对象,即一个行为类似函数的对象。通过在仿函数对象后面加上( )实现函数调用,示例程序如下:

#include<functional>
#include<iostream>
using namespace std;

int main()
{
    greater<int> ig;
    cout << boolalpha << ig(4, 6) << endl; //false
    cout << greater<int>()(6, 4) << endl;  //true
    return 0;
}

greater<int>( )(6, 4)的用法是greater<int>( )产生一个临时的(无名)对象,之后的(4,6)才是指定两个参数4,6。当包含无名对象的语句执行结束时,无名对象的生命周期也就结束了。仿函数在STL中的位置如图所示,是作为STL某些算法的参数出现的。
这里写图片描述
STL仿函数若按照操作数个数分类可分为一元和二元仿函数,若以功能划分,可分为算术运算、关系运算、逻辑运算三大类。程序中若要使用仿函数,应该含入<functional>头文件。
比起一般函数,仿函数具有以下优点:
1. 仿函数是智能型函数(行为类似函数的对象)。
    仿函数是行为类似函数的对象,同时可以拥有成员函数和成员变量,这意味着仿函数可以拥有状态。
2. 每个仿函数都有自己的型别。
3. 仿函数比一般函数快。

二、预定义仿函数分类

  • 算术类仿函数
    STL内建的算术类仿函数,支持加法、减法、乘法、除法、模数和否定运算,除了否定运算为一元运算,其他都是二元运算且支持模版参数template<class T>。
运算格式
加法plus<T>
减法minus<T>
乘法multiplies<T>
除法divides<T>
模取modulus<T>
否定negate<T>


以下为6个算术类仿函数

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 plus : 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; }
};

这些仿函数所产生的对象,用法和一般函数完全相同。当然也可以产生一个无名的临时对象来履行函数功能。下面的示例显示两种仿函数用法:

#include<functional>
#include<iostream>
using namespace std;

int main()
{
    //第一种用法
    plus<int> plusobj;
    minus<int> minusobj;
    multiplies<int> multipliesobj;
    divides<int> dividesobj;
    modulus<int> modulusobj;
    negate<int> negateobj;

    cout << plusobj(3, 5) << endl;
    cout << minusobj(3, 5) << endl;
    cout << multipliesobj(3, 5) << endl;
    cout << dividesobj(3, 5) << endl;
    cout << modulusobj(3, 5) << endl;
    cout << negateobj(3) << endl;

    //第二种用法
    cout << plus<int>()(3, 5) << endl;
    cout << minus<int>()(3, 5) << endl;
    cout << multiplies<int>()(3, 5) << endl;
    cout << divides<int>()(3, 5) << endl;
    cout << modulus<int>()(3, 5) << endl;
    cout << negate<int>()(3) << endl;

    return 0;
}

运行结果:
这里写图片描述

  • 关系运算类仿函数
    STL内建的关系运算类仿函数,支持等于、不等于、大于、大于等于、小于、小于等于等6种运算,每个都是二元运算且支持模版参数template<class T>。
关系运算格式
等于equal_to<T>
不等于not_equal_to<T>
大于greater<T>
大于等于greater_equal<T>
小于less<T>
小于等于less_equal<T>


以下为6个关系运算类仿函数

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 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 : 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; }
};

这些仿函数所产生的对象,用法和一般函数完全相同。当然也可以产生一个无名的临时对象来履行函数功能。下面的示例显示两种仿函数用法:

#include<functional>
#include<iostream>
using namespace std;

int main()
{
    //第一种用法
    equal_to<int> equal_to_obj;
    not_equal_to<int> not_equal_to_obj;
    greater<int> greater_obj;
    greater_equal<int> greater_equal_obj;
    less<int> less_obj;
    less_equal<int> less_equal_obj;

    cout << equal_to_obj(3, 5) << endl;
    cout << not_equal_to_obj(3, 5) << endl;
    cout << greater_obj(3, 5) << endl;
    cout << greater_equal_obj(3, 5) << endl;
    cout << less_obj(3, 5) << endl;
    cout << less_equal_obj(3, 5) << endl;

    //第二种用法
    cout << equal_to<int>()(3, 5) << endl;
    cout << not_equal_to<int>()(3, 5) << endl;
    cout << greater<int>()(3, 5) << endl;
    cout << greater_equal<int>()(3, 5) << endl;
    cout << less<int>()(3, 5) << endl;
    cout << less_equal<int>()(3, 5) << endl;

    return 0;
}

运行结果:
这里写图片描述

  • 逻辑运算类仿函数
    STL内建的逻辑运算仿函数,支持逻辑运算中And、Or、Not三种运算,前两个是二元运算,Not是一元运算且支持模版参数template<class T>。
逻辑运算格式
逻辑与 Andlogical_and<T>
逻辑或 Orlogical_or<T>
逻辑非 Notlogical_not<T>


以下为3个逻辑运算类仿函数

template<class T>
struct logical_and : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x && y; }
};

template<class T>
struct logical_or : public binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x || y; }
};

template<class T>
struct logical_not : public unary_function<T, bool> {
    bool operator()(const T& x) const { return !x; }
};

这些仿函数所产生的对象,用法和一般函数完全相同。当然也可以产生一个无名的临时对象来履行函数功能。下面的示例显示两种仿函数用法:

#include<functional>
#include<iostream>
using namespace std;

int main()
{
    //第一种用法
    logical_and<int> and_obj;
    logical_or<int> or_obj;
    logical_not<int> not_obj;

    cout << and_obj(3, 5) << endl;
    cout << and_obj(0, false) << endl;
    cout << or_obj(3, 5) << endl;
    cout << or_obj(3, 0) << endl;
    cout << not_obj(true) << endl;

    //第二种用法
    cout << logical_and<int>()(3, 5) << endl;
    cout << logical_or<int>()(3, 5) << endl;
    cout << logical_not<int>()(3) << endl;

    return 0;
}

运行结果:
这里写图片描述

三、自制仿函数

自制仿函数即指通过自己定义一个仿函数类,然后生成仿函数对象进行函数调用。而在仿函数类中,要重载operator( )运算符以成为仿函数类。例如:

class AddValue {
    private:
        int theValue;
    public:
        AddValue(int v) : theValue(v) { }
        void operator() (int& elem) const {
            elem += theValue;
        }
};

上例中的AddValue仿函数类生成函数对象时需要首先构函数对象,传入theValue的初值,如AddValue(10)。
也可以使用结构体进行构造,如下。在使用时只需传入型别参数。

template<class T>
struct display{
    void operator()(const T& x) {
        std::cout << x << ' ';
    }
};
....
vector<int> coll;
for_each(coll.begin(), coll.end(), display<int>())
### C++ STL 仿函数的概念 在C++标准模板库(STL)中,仿函数(Functor),也被称为函数对象(function object)[^1]。这类对象的行为类似于函数,可以被调用并携带状态信息。 仿函数本质上是一个重载了`operator()`运算符的类实例。这意味着可以通过像调用普通函数一样来调用该类型的对象,并且可以在不改变接口的情况下维护内部状态或实现更复杂的逻辑。 ### 创建与使用仿函数的方法 为了创建一个仿函数,需定义一个新的类并在其中重写`operator()`成员函数。下面展示了一个简单的例子: ```cpp struct MultiplyBy { int factor; // 构造器初始化factor值 explicit MultiplyBy(int f): factor(f){} // 定义operator()使得此结构体可作为函数调用 int operator()(int value)const{ return value * factor; } }; ``` 这段代码实现了乘法操作的功能封装,在构造时指定乘数(factor),之后每次调用都返回输入参数value乘以此固定倍率的结果。 ### 实际应用场景下的仿函数应用案例 #### 自定义排序规则 当需要对容器内的元素按照特殊条件排序时,就可以利用仿函数来自定义比较方式。比如按降序排列整型向量: ```cpp #include <algorithm> #include <iostream> #include <vector> // 定义仿函数用于两个整数之间的大小关系判断(此处为大于) struct Greater { bool operator()(int a, int b) const { return a > b; } }; int main(){ std::vector<int> vec = {1, 5, 3, 2, 4}; std::sort(vec.begin(), vec.end(), Greater()); for (auto v : vec){ std::cout << v << " "; } return 0; } ``` 上述程序会输出 `5 4 3 2 1`, 表明已经成功地按照从大到小顺序进行了排序。 #### 配合STL算法迭代处理集合项 除了参与排序外,仿函数还经常与其他STL通用算法配合工作,如遍历整个序列并对每个元素施加相同的操作。例如,计算一系列数值总和或者统计满足某些属性的对象数量等场景下都非常有用。 ```cpp #include <numeric> #include <iostream> #include <vector> class SumWithOffset { public: SumWithOffset(double offset_) : sum_(0), offset(offset_){} void operator()(double val){ sum_ += val + offset; } double getSum()const{return sum_;} private: double sum_; double offset; }; int main(){ std::vector<double> numbers{1., 2., 3., 4.}; SumWithOffset summer(1.); std::for_each(numbers.begin(),numbers.end(),summer); std::cout<<"Total:"<<summer.getSum()<<'\n'; return 0; } ``` 这里演示的是累加带有偏移量offset的一组浮点数的过程。通过自定义的仿函数Summer完成这一任务。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值