STL --- 六. 仿函数 Functors

目录

1、仿函数的定义和作用

2、仿函数的分类和使用

3、仿函数的适配器

4、 仿函数的适配器 示例

5、仿函数的示例

6、仿函数和函数对象 区别


1、仿函数的定义和作用

仿函数是一种重载了函数调用运算符operator()的类或结构体,它可以像函数一样被调用。

仿函数可以接受参数并返回值,可以用于STL算法中的函数对象参数,也可以用于函数指针的替代。

仿函数的作用主要有以下几点:

(1)提供一种灵活的方式来实现函数对象,可以根据实际需求定制自己的函数对象,比如排序、查找等算法。

(2)仿函数可以封装函数参数,使得算法可以接受不同类型的参数,而不仅仅是简单的数据类型,这样可以增加算法的通用性。

(3)仿函数可以保存状态,可以在多次调用之间保持状态,这样可以避免在每次调用时都需要重新计算。

(4)仿函数可以用于函数指针的替代,因为函数指针只能指向全局函数或静态成员函数,而仿函数可以指向任意类型的函数,包括成员函数和非静态成员函数。

总之,仿函数是一种非常灵活和强大的工具,可以用于实现各种算法和数据结构,提高程序的可读性和可维护性。


2、仿函数的分类和使用

仿函数是一种重载了函数调用运算符(operator())的类或结构体,它可以像函数一样被调用。

仿函数可以接受参数,也可以返回值。

根据仿函数的功能和特点,可以将其分为以下几种类型:

(1)一元仿函数:只接受一个参数的仿函数。例如:unary_function、negate、not1等。

(2)二元仿函数:接受两个参数的仿函数。例如:binary_function、plus、minus、multiplies等。

(3)关系仿函数:用于比较两个值的大小关系,通常返回bool类型的值。例如:less、greater、equal_to等。

(4)逻辑仿函数:用于逻辑运算,通常返回bool类型的值。例如:logical_and、logical_or、logical_not等。

(5)绑定仿函数:用于将一个或多个参数与函数绑定起来,形成一个新的函数对象。例如:bind1st、bind2nd、mem_fun等。

(6)适配仿函数:用于将一个仿函数适配成另一个仿函数,以满足不同的需求。例如:not2、compose1、compose2等。

优点:使用仿函数可以简化代码,提高效率。

可以将仿函数作为STL算法的参数,对容器中的元素进行处理,也可以在自定义容器中使用仿函数来实现排序、查找等操作。


3、仿函数的适配器

仿函数的适配器是一种特殊的函数对象,它可以将一个仿函数转换为另一个仿函数,或者将一个普通函数指针转换为仿函数。

STL中提供了多种仿函数适配器,包括:

(1)bind1st和bind2nd:将一个二元函数对象转换为一个一元函数对象,其中一个参数已经绑定到指定值。

(2)not1和not2:将一个一元或二元函数对象转换为它们的逻辑非。

(3)ptr_fun:将一个普通函数指针转换为一个仿函数对象。

(4)mem_fun和mem_fun_ref:将一个成员函数指针转换为一个仿函数对象,该仿函数对象可以作为STL算法的参数。

(5)compose1和compose2:将两个仿函数对象组合成一个新的仿函数对象,其中一个仿函数对象的输出作为另一个仿函数对象的输入。

这些适配器可以帮助我们更方便地使用STL算法,同时也可以提高代码的可读性和可维护性。

4、 仿函数的适配器 示例

(1)普通函数指针适配器

#include 
#include 
#include 

bool greaterThan(int a, int b) {
    return a > b;
}

int main() {
    std::vector vec = {5, 2, 3, 1, 4};
    std::sort(vec.begin(), vec.end(), greaterThan);
    for (auto i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

// 输出:5 4 3 2 1

(2)成员函数指针适配器
 

#include 
#include 
#include 

class Person {
public:
    Person(int age) : age_(age) {}
    bool greaterThan(Person* p) {
        return age_ > p->age_;
    }
private:
    int age_;
};

int main() {
    std::vector vec = {new Person(5), new Person(2), new Person(3), new Person(1), new Person(4)};
    std::sort(vec.begin(), vec.end(), [](Person* a, Person* b) { return a->greaterThan(b); });
    for (auto i : vec) {
        std::cout << i->greaterThan(nullptr) << " ";
    }
    std::cout << std::endl;
    return 0;
}

// 输出结果为:1 1 1 1 1

(3)bind适配器

#include 
#include 
#include 
#include 

int main() {
    std::vector vec = {5, 2, 3, 1, 4};
    std::sort(vec.begin(), vec.end(), std::bind(std::greater(), std::placeholders::_2, std::placeholders::_1));
    for (auto i : vec) {
        std::cout << i << " ";
    }
    std::cout << std::endl;
    return 0;
}

// 输出结果为:1 2 3 4 5。

(4)lambda表达式适配器

#include 
#include 
#include 

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


// 输出结果为:5 4 3 2 1。

5、仿函数的示例

以下是一个简单的仿函数示例,它将一个数字加上一个常数值:

#include 

class AddConstant {
public:
    AddConstant(int constant) : constant_(constant) {}

    // 重载 () 运算符,使对象可以像函数一样被调用
    int operator()(int number) const {
        return number + constant_;
    }

private:
    int constant_;
};

int main() {
    AddConstant add5(5); // 创建一个将数字加 5 的仿函数对象

    std::cout << add5(10) << std::endl; // 输出 15

    return 0;
}

在上面的示例中,`AddConstant` 类是一个仿函数,它接受一个整数常数值,并将其存储在私有成员变量 `constant_` 中。

它还重载了 `()` 运算符,使对象可以像函数一样被调用。`operator()` 接受一个整数参数,并将其加上常数值后返回结果。

在 `main` 函数中,我们创建了一个 `AddConstant` 对象 `add5`,它将数字加上 5。我们将数字 10 传递给 `add5` 对象,它返回 15。

6、仿函数和函数对象 区别

STL中的仿函数和函数对象都是用来代替函数的一种机制,但它们之间还是有一些区别的:

(1)仿函数是一个类,而函数对象是一个对象。

(2)仿函数可以重载函数调用运算符operator(),可以像函数一样被调用,而函数对象不能重载函数调用运算符。

(3)仿函数可以保存状态,因为它是一个类,可以有成员变量。而函数对象不可以保存状态,因为它只是一个对象,没有成员变量。

(4)仿函数可以被继承,可以变成一个新的仿函数。函数对象不能被继承。

综上所述:

虽然仿函数和函数对象都可以用来代替函数,但在使用时需要根据实际情况选择。

如果需要保存状态或者需要继承,可以选择仿函数;

如果只是简单地替代函数,可以选择函数对象。

你可能感兴趣的:(STL,c++,开发语言)