【C++ STL仿函数】详细介绍


在C++标准模板库(STL)中,仿函数(Functor),也称为函数对象,是一个行为类似函数的对象。仿函数通过重载函数调用运算符 (),使对象可以像函数一样被调用。仿函数在STL中广泛用于算法和容器的自定义操作,因为它们不仅可以像普通函数一样调用,还可以携带状态和数据,从而提供更强的灵活性和功能性。

1. 仿函数的基本概念

仿函数是一个类或结构体的对象,该类或结构体重载了函数调用运算符 ()。当我们创建一个仿函数的实例并使用 () 调用它时,实际上是在调用该对象的 operator() 方法。

示例:简单的仿函数
#include <iostream>

struct Square {
    int operator()(int x) const {
        return x * x;
    }
};

int main() {
    Square square;
    std::cout << square(5) << std::endl; // 输出 25
    return 0;
}

在这个例子中,Square 是一个仿函数,它的 operator() 方法计算输入整数的平方。

2. 仿函数与普通函数的对比

普通函数是编译时无法携带状态的,而仿函数可以通过成员变量存储状态,从而在调用时使用这些状态。

示例:携带状态的仿函数
#include <iostream>

struct Adder {
    int base;
    
    Adder(int b) : base(b) {}

    int operator()(int x) const {
        return base + x;
    }
};

int main() {
    Adder add5(5);
    std::cout << add5(10) << std::endl; // 输出 15
    return 0;
}

在这个例子中,Adder 仿函数通过 base 成员变量携带了一个状态 5,并在每次调用时将其与输入值相加。

3. STL中的仿函数

STL 中的许多算法和容器都可以使用仿函数。例如,std::sort 可以通过仿函数自定义排序规则,std::for_each 可以使用仿函数执行特定操作。

示例:使用仿函数进行排序
#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 (int v : vec) {
        std::cout << v << " "; // 输出 5 4 3 2 1
    }
    return 0;
}

在这个例子中,Greater 仿函数用于指定排序时应使用大于关系,从而实现降序排序。

4. 标准库中的仿函数

C++ 标准库(尤其是在 <functional> 头文件中)提供了许多常用的仿函数。它们大多是用于常见操作的模板类。

  • 算术仿函数std::plusstd::minusstd::multipliesstd::dividesstd::modulusstd::negate

    例如,std::plus<int>()(3, 4) 返回 7,相当于 3 + 4

  • 关系仿函数std::equal_tostd::not_equal_tostd::greaterstd::lessstd::greater_equalstd::less_equal

    例如,std::greater<int>()(4, 3) 返回 true

  • 逻辑仿函数std::logical_andstd::logical_orstd::logical_not

    例如,std::logical_and<bool>()(true, false) 返回 false

  • 位运算仿函数std::bit_andstd::bit_orstd::bit_xorstd::bit_not

5. 绑定器和适配器

C++ 还提供了一些工具,可以将仿函数、函数指针或普通函数进行“绑定”或“适配”,从而改变其行为或简化调用。

  • std::bind:可以将仿函数的某些参数绑定为固定值,从而创建新的仿函数。

    #include <iostream>
    #include <functional>
    
    int add(int a, int b) {
        return a + b;
    }
    
    int main() {
        auto add5 = std::bind(add, 5, std::placeholders::_1); // 将第一个参数固定为 5
        std::cout << add5(3) << std::endl; // 输出 8
        return 0;
    }
    
  • std::function:是一个通用的函数包装器,可以保存任何可调用对象(包括仿函数、函数指针、lambda 表达式等)。

    #include <iostream>
    #include <functional>
    
    int main() {
        std::function<int(int, int)> func = [](int a, int b) { return a * b; };
        std::cout << func(3, 4) << std::endl; // 输出 12
        return 0;
    }
    

6. Lambda表达式与仿函数

在现代C++中,lambda表达式(匿名函数)提供了一种更简洁的方式来创建临时仿函数。Lambda 表达式常用于算法中进行自定义操作,替代传统的仿函数类。

示例:使用lambda替代仿函数
#include <algorithm>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {1, 5, 3, 2, 4};
    std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; });

    for (int v : vec) {
        std::cout << v << " "; // 输出 5 4 3 2 1
    }
    return 0;
}

在这个例子中,lambda表达式 [](int a, int b) { return a > b; } 实现了与前面 Greater 仿函数相同的功能,但代码更简洁。

7. 自定义仿函数的用途

仿函数在STL中有很多应用场景:

  • 自定义排序规则:通过仿函数定制排序算法中的排序逻辑。
  • 自定义操作:在 std::for_each 等算法中,通过仿函数执行复杂的操作。
  • 状态管理:通过仿函数的成员变量在算法中保存状态信息。

8. 总结

仿函数是C++中一个强大且灵活的特性,它结合了对象的状态和函数的行为,使得在STL中使用自定义操作变得更加方便。通过理解仿函数的概念和应用,程序员可以编写出更灵活、更高效的代码。

关键点总结:

  • 仿函数是对象化的函数:它们通过重载 operator() 来实现函数调用的行为。
  • 标准库提供了常用的仿函数:如算术、关系、逻辑、位运算等仿函数。
  • 仿函数可以携带状态:这使得它们比普通函数更加灵活。
  • Lambda 表达式是现代 C++ 中更简洁的仿函数实现方式
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值