• 浅谈STL|STL函数对象篇


    在这里插入图片描述

    一.函数对象概念

    概念:

    ·重载函数调用操作符的类,其对象常称为函数对象
    ·函数对象使用重载的()时,行为类似函数调用,也叫仿函数

    本质:

    函数对象(仿函数)是一个类,不是一个函数

    特点

    • 函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值;
    • 函数对象超出普通函数的概念,函数对象可以有自己的状态;
    • 函数对象可以作为参数传递;

    函数对象可以像普通函数一样被调用,并且可以接受参数和返回值。通过重载函数调用操作符 operator(),函数对象可以在使用时表现得像函数一样。

    函数对象的一个优势是它可以拥有自己的状态。由于函数对象实际上是一个类的对象,所以它可以拥有成员变量,这些变量可以在每次调用时保持状态并进行更新。这使得函数对象可以在多次调用之间维护一些信息。

    此外,函数对象还可以作为参数传递给其他函数。许多标准库的算法函数,例如 std::sortstd::transform 等,可以接受函数对象作为参数,以定义算法的具体操作。通过将函数对象传递给其他函数,我们可以实现更灵活、可定制的功能。

    以下是一个简单的示例,展示了函数对象的用法:

    #include 
    
    class MyFunctor
    {
    public:
        void operator()(int x) const
        {
            // 在回调时输出消息
            std::cout << "Function object called with " << x << std::endl;
        }
    };
    
    void callWithFunctor(const MyFunctor& functor, int value)
    {
        functor(value);  // 调用函数对象
    }
    
    int main()
    {
        MyFunctor functor;
        callWithFunctor(functor, 42);  // 传递函数对象给函数,并进行调用
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在上述示例中,MyFunctor 是一个函数对象,我们将它作为参数传递给 callWithFunctor 函数,并在函数内部调用函数对象。

    总结来说,函数对象可以像普通函数一样被调用,可以接受参数和返回值,可以拥有自己的状态,并可以作为参数传递给其他函数,这使得函数对象在编程中非常有用和灵活。


    函数对象相比于普通函数具有一个重要的优势,那就是函数对象可以拥有自己的状态。这意味着函数对象可以在多次调用之间记录和维护自己的内部数据。

    普通函数是无状态的,它们不会保留任何关于之前调用的信息。每次调用函数时,它们只是根据传入的参数执行相应的操作,并返回结果。

    而函数对象则可以在每次调用时保持状态,并根据状态的变化来改变行为。这种状态是通过函数对象的成员变量来实现的。函数对象的成员变量可以记录在调用过程中需要持久化的数据,而这些数据会在不同的函数调用之间持续存在。

    这种函数对象的状态可以非常有用。它允许我们在不同的调用之间共享和利用数据,从而实现更复杂的行为。例如,我们可以使用函数对象来实现一个计数器,每次调用增加计数值,并在后续的调用中使用该值。

    以下是一个简单的示例,展示了函数对象中保存状态的功能:

    #include 
    
    class Counter
    {
    public:
        Counter() : count(0) {}
    
        int operator()()
        {
            return ++count;
        }
    
    private:
        int count;
    };
    
    int main()
    {
        Counter counter;
    
        std::cout << counter() << std::endl;  // 输出:1
        std::cout << counter() << std::endl;  // 输出:2
        std::cout << counter() << std::endl;  // 输出:3
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在上述示例中,Counter 是一个函数对象,它通过重载函数调用操作符 operator() 来实现计数的功能。每次调用 Counter 对象时,计数器的值会增加,并返回新的计数值。

    总结而言,函数对象相比普通函数具有自己的状态,这使得它们可以在多次调用之间保持数据,并根据状态的变化改变行为。这种功能使得函数对象在许多应用场景中非常有用,例如实现计数器、缓存等。

    二.谓词

    概念:

    • 返回bool类型的仿函数称为谓词
    • 如果operator()接受一个参数,那么叫做一元谓词
    • 如果operator()接受两个参数,那么叫做二元谓词

    返回 bool 类型的仿函数被称为谓词(Predicate)。谓词通常用于对某些条件进行判断,并返回相应的布尔值。

    此外,根据 operator() 接受的参数数量,可以将谓词进一步分类为一元谓词(Unary Predicate)和二元谓词(Binary Predicate)。

    • 一元谓词是指 operator() 只接受一个参数的谓词。它用于对单个对象进行判断,返回一个布尔值。一元谓词通常用于像 std::find_ifstd::remove_if 等算法中。
    • 二元谓词是指 operator() 接受两个参数的谓词。它用于对两个对象进行比较或判断,返回一个布尔值。二元谓词通常用于像 std::sortstd::find 等算法中,用于指定排序规则或比较条件。

    通过使用谓词,我们可以灵活地对对象进行条件判断和过滤。

    以下是一个简单的示例,展示了一元谓词和二元谓词的概念:

    #include 
    #include 
    #include 
    
    // 一元谓词
    struct IsEven
    {
        bool operator()(int n) const
        {
            return n % 2 == 0;
        }
    };
    
    // 二元谓词
    struct IsLess
    {
        bool operator()(int a, int b) const
        {
            return a < b;
        }
    };
    
    int main()
    {
        std::vector<int> numbers = { 1, 2, 3, 4, 5 };
        
        // 使用一元谓词查找第一个偶数
        auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());
        if (it != numbers.end())
        {
            std::cout << "First even number: " << *it << std::endl;
        }
        
        // 使用二元谓词排序
        std::sort(numbers.begin(), numbers.end(), IsLess());
        
        // 输出排序结果
        std::cout << "Sorted numbers: ";
        for (int num : numbers)
        {
            std::cout << num << " ";
        }
        std::cout << std::endl;
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    在上述示例中,IsEven 是一个一元谓词,通过重载 operator() 来判断一个数字是否为偶数。IsLess 是一个二元谓词,通过重载 operator() 实现了两个数字的比较操作。

    我们在主函数中使用了一元谓词来查找第一个偶数,并使用二元谓词对数组进行排序。

    总结来说,返回 bool 类型的函数对象被称为谓词。根据 operator() 接受的参数数量,谓词可以进一步分类为一元谓词和二元谓词。谓词在标准库的算法中大量使用,用于自定义比较和条件判断。


    find_if

    std::find_if 是 C++ 标准库中的一个算法函数,它的作用是在给定的范围内查找满足指定条件的元素,并返回第一个满足条件的元素的迭代器。

    函数签名如下所示:

    template <class InputIt, class UnaryPredicate>
    InputIt find_if(InputIt first, InputIt last, UnaryPredicate p);
    
    • 1
    • 2

    参数说明:

    • firstlast:表示要查找的元素范围,first 表示范围的起始位置,last 表示范围的结束位置(不包含在范围内)。
    • p:一个一元谓词,用于判断元素是否满足条件。

    函数返回值是一个迭代器,指向范围内第一个满足条件的元素,如果没有找到满足条件的元素,则返回 last

    以下是一个简单的示例,展示了 std::find_if 的使用:

    #include 
    #include 
    #include 
    
    struct IsEven
    {
        bool operator()(int n) const
        {
            return n % 2 == 0;
        }
    };
    
    int main()
    {
        std::vector<int> numbers = { 1, 2, 3, 4, 5 };
    
        // 使用一元谓词查找第一个偶数
        auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());
        if (it != numbers.end())
        {
            std::cout << "First even number: " << *it << std::endl;
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    在上述示例中,我们定义了一个一元谓词 IsEven,用于判断一个数字是否为偶数。然后,我们使用 std::find_if 函数在 numbers 容器中查找第一个满足条件的偶数,并输出结果。

    值得注意的是,std::find_if 在查找到满足条件的元素后,会立即停止搜索并返回该元素的迭代器。如果要查找出多个满足条件的元素,可以使用 std::find_if 结合其他算法函数或循环进行迭代查找。

    三.内建函数对象

    当涉及到内建函数对象时,可以根据它们的功能将它们分为三类: 算术函数对象、逻辑函数对象和关系函数对象。

    1. 算术函数对象:

      • std::plus: 加法操作。
      • std::minus: 减法操作。
      • std::multiplies: 乘法操作。
      • std::divides: 除法操作。
      • std::modulus: 取模操作。
    2. 逻辑函数对象:

      • std::logical_and: 逻辑与操作。
      • std::logical_or: 逻辑或操作。
      • std::logical_not: 逻辑非操作。
    3. 关系函数对象:

      • std::less: 小于比较。
      • std::less_equal: 小于等于比较。
      • std::greater: 大于比较。
      • std::greater_equal: 大于等于比较。
      • std::equal_to: 等于比较。
      • std::not_equal_to: 不等于比较。

    这些函数对象可以通过重载 operator() 来执行特定的操作或比较,它们被设计为与标准库算法一起使用,以提供通用的功能。通过使用这些函数对象,我们可以以一种通用且灵活的方式处理算术、逻辑和关系操作。

    当涉及到内建函数对象时,我们可以通过以下示例来展示它们的使用:

    1. 算术函数对象:
    #include 
    #include 
    
    int main() {
        std::plus<int> add;
    
        int a = 5, b = 10;
    
        int result = add(a, b);
        std::cout << "Addition result: " << result << std::endl;  // 输出:15
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上述示例中,我们使用了 std::plus 函数对象来执行加法操作,将数字 ab 相加,并将结果存储在 result 变量中。

    1. 逻辑函数对象:
    #include 
    #include 
    
    int main() {
        std::logical_and<bool> logicAnd;
    
        bool value1 = true, value2 = false;
    
        bool result = logicAnd(value1, value2);
        std::cout << "Logical AND result: " << std::boolalpha << result << std::endl;  // 输出:false
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上述示例中,我们使用了 std::logical_and 函数对象来执行逻辑与操作,对 value1value2 进行逻辑与运算,并将结果存储在 result 变量中。

    1. 关系函数对象:
    #include 
    #include 
    
    int main() {
        std::less<int> lessThan;
    
        int a = 5, b = 10;
    
        bool result = lessThan(a, b);
        std::cout << "Less than result: " << std::boolalpha << result << std::endl;  // 输出:true
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在上述示例中,我们使用了 std::less 函数对象来执行小于比较,判断 a 是否小于 b,并将结果存储在 result 变量中。

    这些示例演示了如何使用内建函数对象进行算术、逻辑和关系操作。您可以通过实例化适当的函数对象类模板,然后将其用作函数调用,以便执行所需的操作或比较。

    请注意,这些示例可能只是演示了函数对象的一小部分用法,这些函数对象在标准库的算法和其他使用场景中非常有用。

    好的,下面是一个整理成表格的例子,展示了内建函数对象及其用途的示例。

    函数对象用途示例
    std::plus加法操作std::plus()(2, 3) // 输出:5
    std::minus减法操作std::minus()(5, 2) // 输出:3
    std::multiplies乘法操作std::multiplies()(3, 4) // 输出:12
    std::divides除法操作std::divides()(10, 2) // 输出:5
    std::modulus取模操作std::modulus()(10, 3) // 输出:1
    std::logical_and逻辑与操作std::logical_and()(true, false) // 输出:false
    std::logical_or逻辑或操作std::logical_or()(true, false) // 输出:true
    std::logical_not逻辑非操作std::logical_not()(true) // 输出:false
    std::less小于比较std::less()(2, 5) // 输出:true
    std::less_equal小于等于比较std::less_equal()(5, 5) // 输出:true
    std::greater大于比较std::greater()(5, 2) // 输出:true
    std::greater_equal大于等于比较std::greater_equal()(5, 5) // 输出:true
    std::equal_to相等比较std::equal_to()(2, 2) // 输出:true
    std::not_equal_to不等比较std::not_equal_to()(2, 5) // 输出:true
  • 相关阅读:
    SpringCloud环境搭建 --- Rest使用
    Redis_04_Redis事务
    Debian 11 AMD Install driver(wifi...)
    前端JS基础第三篇:七道例题带你弄懂this指向问题
    菜鸟学Kubernetes(K8s)系列——(番外)安装Ingress-Nginx(工作原理)
    微信小程序获取元素的高度
    解决mac系统终端无法使用vpn
    LeetCode·每日一题·850.矩形面积 || ·【离散化+扫描线+数组】
    Spring Cloud之ElasticSearch的学习【详细】
    单细胞分析+实验验证,多重buff加身,学会你也能发7分+。
  • 原文地址:https://blog.csdn.net/m0_73731708/article/details/132882542