STL函数对象
文章目录
- STL函数对象
- 1.基本概念
- 2.使用方法
- 1. 简单函数对象示例
- 2. 函数对象作为算法参数
- 3. Lambda表达式作为函数对象
- 2.一元谓词和二元谓词
- 1.一元谓词
- 2.二元谓词
- 3.总结
- 3.算术仿函数
- 1.使用示例
- 2.Lambda表达式的替代
- 4.关系仿函数
- 5.逻辑仿函数
C++中的函数对象(Function Object),也常被称为仿函数(Functor),是一种模拟函数行为的类对象。它们允许用户自定义操作,并能像普通函数那样被调用,同时还能携带状态,这是普通函数所不具备的能力。函数对象是实现泛型编程、算法定制等高级技术的关键组件之一。下面概述了函数对象的基本概念和使用方法:
1.基本概念
- 类定义:函数对象通常是一个重载了
()
操作符的类。这个操作符使得该类的对象可以像函数一样被调用。 - 状态携带:与普通函数不同,函数对象可以拥有成员变量,从而在不同的调用之间保持状态。
- 类型要求:为了能够用于标准库算法中,函数对象需要满足可调用对象的要求,即至少要有一个
operator()
成员函数。
2.使用方法
1. 简单函数对象示例
#include <iostream>
// 定义一个简单的函数对象类,重载了()操作符
class Adder {
public:
// 构造函数可以初始化内部状态
Adder(int add_value) : value(add_value) {}
// 重载()操作符,使得对象可以像函数一样被调用
int operator()(int x) {
return x + value;
}
private:
int value; // 成员变量,保存加到输入值上的额外值
};
int main() {
Adder addFive(5); // 创建一个Adder对象,初始化加值为5
std::cout << addFive(10) << std::endl; // 调用仿函数,输出15
return 0;
}
2. 函数对象作为算法参数
C++标准库中的许多算法都接受函数对象作为参数,以定制其行为。例如,std::sort
可以通过传递自定义比较函数来改变排序规则。
#include <algorithm>
#include <vector>
#include <iostream>
// 一个用于降序比较的仿函数
struct DescComp {
bool operator()(int a, int b) {
return a > b;
}
};
int main() {
std::vector<int> vec = {1, 3, 5, 2, 4};
// 使用自定义的降序比较仿函数进行排序
std::sort(vec.begin(), vec.end(), DescComp());
for(int i : vec) {
std::cout << i << " ";
}
// 输出:5 4 3 2 1
return 0;
}
3. Lambda表达式作为函数对象
从C++11开始,Lambda表达式提供了一种更简洁的方式创建匿名函数对象,它可以直接在代码中定义并使用。
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
// 使用Lambda表达式作为自定义排序规则
std::sort(vec.begin(), vec.end(), [](int a, int b) {
return a > b; // 降序排列
});
for(int i : vec) {
std::cout << i << " ";
}
// 输出:5 4 3 2 1
return 0;
}
通过上述示例,可以看到函数对象在C++中提供了强大的灵活性和定制能力,是泛型编程和算法设计中的重要工具。
2.一元谓词和二元谓词
C++中的一元谓词和二元谓词是两种特定类型的函数对象,它们在标准模板库(STL)的算法中扮演着重要的角色,用于定制算法的行为。以下是它们的基本概念和使用方法:
1.一元谓词
基本概念:
- 一元谓词是只接受一个参数的函数对象,并返回一个布尔值(
bool
)。 - 这个函数对象通常用来测试或判断传入的参数是否满足某个条件。
- 在STL算法中,一元谓词常用于从容器中选择满足特定条件的元素,例如
std::find_if
。
使用示例:
#include <algorithm>
#include <vector>
#include <iostream>
// 一元谓词函数对象,检查一个数是否为偶数
struct IsEven {
bool operator()(int x) {
return x % 2 == 0;
}
};
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6};
auto it = std::find_if(numbers.begin(), numbers.end(), IsEven());
if(it != numbers.end())
std::cout << "The first even number is: " << *it << std::endl;
else
std::cout << "No even number found." << std::endl;
return 0;
}
2.二元谓词
基本概念:
- 二元谓词接受两个参数,并返回一个布尔值。
- 它们通常用于比较这两个参数是否满足某种关系,如小于、大于、等于等。
- 在STL中,二元谓词广泛应用于排序算法(如
std::sort
)、查找算法(如std::binary_search
)等,用以定义元素间的比较规则。
使用示例:
#include <algorithm>
#include <vector>
#include <iostream>
// 二元谓词函数对象,检查第一个数是否大于第二个数
struct GreaterThan {
bool operator()(int a, int b) {
return a > b;
}
};
int main() {
std::vector<int> values = {5, 2, 9, 1, 5, 6};
// 使用二元谓词进行降序排序
std::sort(values.begin(), values.end(), GreaterThan());
for(int val : values) {
std::cout << val << " ";
}
// 输出:9 6 5 5 2 1
return 0;
}
3.总结
无论是哪种谓词,它们的核心作用都是提供一个逻辑判断,使得STL算法能够基于这些逻辑判断来处理数据。一元谓词适用于单个元素的条件筛选,而二元谓词则用于定义元素间的关系,比如排序或查找时的比较逻辑。随着C++11及之后版本对Lambda表达式的支持,直接在算法中内联定义谓词变得更加方便快捷。
3.算术仿函数
C++ STL(标准模板库)提供了一系列算术仿函数(Arithmetic Functors),它们是对基本数学运算的封装,使得这些运算可以像函数对象一样被使用,尤其是在算法中进行定制操作时非常有用。以下是一些常用的算术仿函数及其简单说明:
- plus:定义了加法操作,重载了
operator()
以执行加法。 - minus:定义了减法操作。
- multiplies:实现了乘法操作。
- divides:提供了除法操作。
- modulus:用于取模运算。
- negate:执行取负操作。
1.使用示例
这些仿函数位于<functional>
头文件。
#include <iostream>
#include <functional>
#include <algorithm> // 用于std::transform
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
std::vector<int> results;
// 使用plus仿函数将每个元素自身相加(即每个元素乘以2)
results.resize(numbers.size());
std::transform(numbers.begin(), numbers.end(), results.begin(), std::plus<int>());
// 输出结果
for(int res : results) {
std::cout << res << " ";
}
// 输出:2 4 6 8 10
return 0;
}
在这个例子中,std::transform
算法结合std::plus<int>()
仿函数,将numbers
容器中的每个元素与其自身相加,结果存储在results
容器中。
2.Lambda表达式的替代
虽然算术仿函数非常有用,但在C++11及以后的版本中,Lambda表达式提供了更加灵活和直观的方式来定义这样的操作,特别是在复杂逻辑或需要访问外部变量时。然而,对于简单的数学运算,直接使用STL提供的算术仿函数可以简化代码,提高可读性。
4.关系仿函数
关系仿函数封装了基本的比较运算符,位于<functional>
头文件中。
- equal_to:测试两个参数是否相等。
- not_equal_to:测试两个参数是否不相等。
- greater:测试第一个参数是否大于第二个参数。
- less:测试第一个参数是否小于第二个参数。
- greater_equal:测试第一个参数是否大于等于第二个参数。
- less_equal:测试第一个参数是否小于等于第二个参数。
#include <iostream>
#include <functional>
#include <algorithm>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
int target = 3;
// 使用equal_to查找目标值
if(std::find_if(vec.begin(), vec.end(), std::bind2nd(std::equal_to<int>(), target)) != vec.end()) {
std::cout << target << " is found in the vector." << std::endl;
} else {
std::cout << target << " is not found in the vector." << std::endl;
}
return 0;
}
5.逻辑仿函数
逻辑仿函数用于组合或反转布尔值,它们也是在<functional>
中定义的,包括:
- logical_and:对两个布尔值执行逻辑与操作。
- logical_or:对两个布尔值执行逻辑或操作。
- logical_not:对一个布尔值执行逻辑非操作。
逻辑仿函数示例
#include <iostream>
#include <functional>
int main() {
bool flag1 = true, flag2 = false;
// 使用逻辑与
if(std::logical_and<bool>()(flag1, flag2)) {
std::cout << "Both flags are true." << std::endl;
} else {
std::cout << "Not both flags are true." << std::endl;
}
// 使用逻辑或
if(std::logical_or<bool>()(flag1, flag2)) {
std::cout << "At least one flag is true." << std::endl;
}
// 使用逻辑非
std::cout << "Negation of flag2: " << std::logical_not<bool>()(flag2) << std::endl;
return 0;
}