可调用对象
介绍
在C++中,可调用对象是指任何可以像函数一样被调用的对象。这些对象可以是函数、函数指针、函数对象(仿函数)或 lambda 表达式。
普通函数
普通函数是最基本的可调用对象。你可以直接通过函数名来调用它们。
#include <iostream>
void sayHello() {
std::cout << "Hello, World!" << std::endl;
}
int main() {
sayHello(); // 调用函数
return 0;
}
函数指针
函数指针是指向函数的指针,可以用来调用指向的函数。它们允许在运行时选择要调用的函数。
#include <iostream>
void sayHello() {
std::cout << "Hello, World!" << std::endl;
}
int main() {
void (*funcPtr)() = sayHello; // 定义函数指针并指向 sayHello
funcPtr(); // 通过函数指针调用函数
return 0;
}
函数对象(仿函数)
函数对象是重载了 operator() 的类的实例。它们可以像普通函数一样被调用,且可以保存状态。
#include <iostream>
class Functor {
public:
void operator()() const {
std::cout << "Hello from Functor!" << std::endl;
}
};
int main() {
Functor f; // 创建函数对象
f(); // 调用函数对象
return 0;
}
Lambda 表达式
Lambda 表达式是 C++11 引入的一种轻量级的可调用对象。它们可以捕获周围的变量,并且可以像函数一样被调用。
#include <iostream>
int main() {
auto lambda = []() {
std::cout << "Hello from Lambda!" << std::endl;
};
lambda(); // 调用 lambda 表达式
return 0;
}
std::function
std::function 是一个通用的可调用对象包装器,可以存储任何可调用对象,包括普通函数、函数指针、函数对象和 lambda 表达式。它提供了统一的接口来调用这些对象。
#include <iostream>
#include <functional>
void sayHello() {
std::cout << "Hello from std::function!" << std::endl;
}
int main() {
std::function<void()> func = sayHello; // 使用 std::function
func(); // 调用
return 0;
}
可调用对象的应用
可调用对象在许多场景中非常有用,例如:
- 回调函数:在事件驱动编程中,常常需要将函数作为参数传递,以便在特定事件发生时调用。
- STL算法:STL(标准模板库)中的许多算法(如
std::sort)接受可调用对象作为参数,以便在排序或查找时使用自定义的比较逻辑。 - 多线程:在多线程编程中,可以将可调用对象传递给线程,以便在新线程中执行。
用法
如果一个对象可以使用调用运算符“()”,()里面可以放参数,这个对象就是可调用对象
可调用对象分类
(1) 函数:函数自然可以调用()运算符,是最典型的可调用对象
(2) 仿函数:具有operator()函数的类对象,此时类对象可以当做函数使用,因此称为仿函数
#include <iostream>
class Test // 有operator()函数
{
public:
void operator()(int i)
{
std::cout << i << std::endl;
std::cout << "hello world" << std::endl;
}
};
int main()
{
Test t; // t此时就是一个仿函数
t(20);
return 0;
}
(3) lambda 表达式:就是匿名函数,普通的函数在使用前需要找个地方将这个函数定义,于是 C++提供了 lambda 表达式,需要函数时直接在需要的地方写一个 lambda 表达式,省去了定义函数的过程,增加开发效率
#include <iostream>
int main()
{
[] {
std::cout << "hello world" << std::endl;
}();
return 0;
}
注意:lambda 表达式很重要,现代 C++程序中,lambda 表达式是大量使用的。
lambda 表达式的格式:最少是“[] {}”,完整的格式为“[] () ->ret {}”。
lambda 各个组件介绍
-
[]代表捕获列表:表示 lambda 表达式可以访问前文的哪些变量。 基本用法
- []表示不捕获任何变量。
- [=]:表示按值捕获所有变量。
- [&]:表示按照引用捕获所有变量。 =,&也可以混合使用
- [=, &i]:表示变量 i 用引用传递,除 i 的所有变量用值传递。
- [&, i]:表示变量 i 用值传递,除 i 的所有变量用引用传递。 当然,也可以捕获单独的变量
- [i]:表示以值传递的形式捕获 i
- [&i]:表示以引用传递的方式捕获 i
-
()代表 lambda 表达式的参数,函数有参数,lambda 自然也有。
-
->ret 表示指定 lambda 的返回值,如果不指定,lambda 表达式也会推断出一个返回值的。
-
{}就是函数体了,和普通函数的函数体功能完全相同
可调用对象的常见用法
(1) 可调用对象作为函数的参数
这里使用函数指针对象举例:
#include <iostream>
void test(int i)
{
std::cout << i << std::endl;
std::cout << "hello world" << std::endl;
}
using pf_type = void(*)(int); // 函数指针
void myFunc(pf_type pf, int i) // 可调用对象作为函数的参数
{
pf(i);
}
int main()
{
myFunc(test, 200);
return 0;
}
参数使用函数指针对象 接收 函数地址,实参&test,&可以省略