当前位置: 首页 > news >正文

C++ 中的函数包装:std::bind()、std::function<>、函数指针与 Lambda

函数包装(Function Wrapping)是一种编程技术,指的是将一个函数(或可调用对象)封装在另一个函数或对象中,以扩展其功能、修改其行为或提供额外的上下文。函数包装的核心思想是通过一个“包装器”来间接调用原始函数,同时可以在调用前后执行额外的逻辑。

函数指针

函数指针是 C++ 中最基础的函数包装方式。可以将函数的地址存储在指针中,并通过该指针调用函数。

#include <iostream>void printHello() {std::cout << "Hello, World!" << std::endl;
}
void printSum(int a, int b) {std::cout << "Sum: " << a + b << std::endl;
}int main() {void (*funcPtr)() = &printHello;funcPtr();  // 输出: Hello, World!void (*funcPtr2)(int, int) = &printSum;funcPtr2(10, 20); // 输出: Sum: 30return 0;
}

void (*funcPtr2)(int, int)

  • funcPtr2:函数指针起的名字,就像变量名一样。
  • *:表明funcPtr2是一个指针,是指向函数的指针,而不是指向简单数据类型的普通指针。
  • void:指出该指针所指向的函数返回值类型为void
  • (int, int):函数的参数列表,该函数接受两个int类型的参数。

优势

  • 简单直接:函数指针的概念简单,易于理解和使用。
  • 性能高:函数指针直接指向函数地址,调用开销小。

缺点

  • 类型不安全:函数指针的类型检查较弱,容易出错。
  • 灵活性差:无法直接绑定成员函数或带有状态的函数。

std::function<>

std::function<> 是 C++11 引入的一个通用函数包装器,它可以存储任何可调用对象(如函数、Lambda 表达式、成员函数等)。

需要头文件:#include <functional>

#include <iostream>
#include <functional>void printHello() {std::cout << "Hello, World!" << std::endl;
}void printSum(int a, int b) {std::cout << "Sum: " << a + b << std::endl;
}int main() {std::function<void()> func = printHello;func();  // 输出: Hello, World!std::function<void(int, int)> func2 = printSum;func2(10, 20);  // 输出: Sum: 30// 接收lambda表达式类型std::function<int(int, int)> func3 = [](int a, int b) {return a * b;};func3(10, 20);  // 输出:30return 0;
}

std::function<void(int, int)> func2 = printSum:

std::function<...>:是一个模板类,用于封装可调用对象。模板参数描述了被封装对象的签名。

void(int, int):模板参数,描述了被封装对象的签名,这里是接受了两个int类型的参数返回类型为void

在代码中,也可以使用using 关键字与 std::function<> 结合使用,用于定义类型别名,从而简化代码并提高可读性。

#include <iostream>
#include <functional>// 使用 using 定义 std::function 类型别名
using IntFunction = std::function<int(int, int)>;// 普通函数
int add(int a, int b) {return a + b;
}int main() {// 使用别名声明 std::function 对象IntFunction func = add;// 调用std::cout << "Result: " << func(2, 3) << std::endl; // 输出 5return 0;
}

优势

  • 通用性强:可以存储任何可调用对象,包括函数、Lambda 表达式、成员函数等。
  • 类型安全std::function<> 提供了类型检查,减少了出错的可能性。

缺点

  • 性能开销:相比于函数指针,std::function<> 有一定的性能开销,尤其是在存储复杂对象时。

std::bind()

std::bind() 是 C++11 引入的一个函数适配器,它可以将函数与参数绑定在一起,生成一个新的可调用对象。

需要头文件:#include <functional>

#include <iostream>
#include <functional>void printSum(int a, int b) {std::cout << "Sum: " << a + b << std::endl;
}int main() {auto boundFunc = std::bind(printSum, 10, std::placeholders::_1);boundFunc(20);  // 输出: Sum: 30return 0;
}

优势

  • 参数绑定:可以将部分参数预先绑定,生成一个新的可调用对象。
  • 灵活性高:可以绑定成员函数、普通函数等。

缺点

  • 可读性差std::bind() 的语法较为复杂,可读性较差。
  • 性能开销:与 std::function<> 类似,std::bind() 也有一定的性能开销。

Lambda 表达式

Lambda 表达式是 C++11 引入的一种匿名函数,它可以在代码中直接定义并使用。

#include <iostream>int main() {auto lambda = [](int a, int b) {std::cout << "Sum: " << a + b << std::endl;};lambda(10, 20);  // 输出: Sum: 30return 0;
}

C++11特性详解-CSDN博客 可看lambda表达式具体使用方法。

优势

  • 简洁:Lambda 表达式可以在代码中直接定义,无需单独声明函数。
  • 捕获外部变量:Lambda 表达式可以捕获外部变量,使得函数更加灵活。

缺点

  • 可读性差:复杂的 Lambda 表达式可能会降低代码的可读性。
  • 性能开销:捕获外部变量时,Lambda 表达式可能会引入额外的性能开销。

其他函数包装方式

除了上述几种方式,C++ 还提供了其他一些函数包装技术,如函数对象(Functor)和成员函数指针。

函数对象(Functor)

函数对象是一个重载了 operator() 的类对象,它可以像函数一样被调用。

#include <iostream>struct Sum {void operator()(int a, int b) const {std::cout << "Sum: " << a + b << std::endl;}
};int main() {Sum sum;sum(10, 20);  // 输出: Sum: 30return 0;
}

成员函数指针

成员函数指针可以指向类的成员函数,并通过对象或指针调用。

#include <iostream>class MyClass {
public:void printHello() {std::cout << "Hello, World!" << std::endl;}void printSum(int a, int b) {std::cout << "Sum: " << a + b << std::endl;}
};int main() {MyClass obj;void (MyClass::*funcPtr)() = &MyClass::printHello;(obj.*funcPtr)();  // 输出: Hello, World!void (MyClass::*funcPtr2)(int, int) = &MyClass::printSum;(obj.*funcPtr2)(10, 20);  // 输出: Sum: 30return 0;
}

总结:

  • 函数指针:适用于简单的函数调用场景,性能要求高。
  • std::function<>:适用于需要存储多种可调用对象的场景,类型安全。
  • std::bind():适用于需要预先绑定参数的场景,灵活性高。
  • Lambda 表达式:适用于需要简洁、灵活的函数定义场景,尤其是需要捕获外部变量的情况。

文章转载自:
http://brutehood.dxwdwl.cn
http://bibliology.dxwdwl.cn
http://antepenult.dxwdwl.cn
http://anabolism.dxwdwl.cn
http://afar.dxwdwl.cn
http://carbonari.dxwdwl.cn
http://cacciatora.dxwdwl.cn
http://annulment.dxwdwl.cn
http://chlorophyllous.dxwdwl.cn
http://apsis.dxwdwl.cn
http://astonishing.dxwdwl.cn
http://bauson.dxwdwl.cn
http://chicory.dxwdwl.cn
http://balalaika.dxwdwl.cn
http://ascetically.dxwdwl.cn
http://boil.dxwdwl.cn
http://bordure.dxwdwl.cn
http://bedsonia.dxwdwl.cn
http://biz.dxwdwl.cn
http://bayesian.dxwdwl.cn
http://canthus.dxwdwl.cn
http://academism.dxwdwl.cn
http://academicals.dxwdwl.cn
http://adenoidectomy.dxwdwl.cn
http://choplogic.dxwdwl.cn
http://castellated.dxwdwl.cn
http://affectionately.dxwdwl.cn
http://ablative.dxwdwl.cn
http://backwater.dxwdwl.cn
http://cabala.dxwdwl.cn
http://www.dtcms.com/a/215857.html

相关文章:

  • 一个开源的多播放源自动采集在线影视网站
  • 15.进程间通信(一)
  • c++复习_第一天(引用+小众考点)
  • 2025吉林CCPC 题解(前六题)
  • 【NLP基础知识系列课程-Tokenizer的前世今生第四课】生物信息中的 Tokenizer 策略:如何切开一段基因?
  • 【NLP基础知识系列课程-Tokenizer的前世今生第五课】从静态到可学:Tokenizer 的自适应演化之路
  • C/C++的OpenCV的锐化
  • ojs导入显示空白页错误信息
  • Ubuntu 下搭建ESP32 ESP-IDF开发环境,并在windows下用VSCode通过SSH登录Ubuntu开发ESP32应用
  • 【android bluetooth 协议分析 02】【bluetooth hal 层详解 6】【高通蓝牙hal主要流程介绍-下】
  • Jmeter一些元件使用的详细记录
  • 详解MYSQL索引失效问题排查
  • 如何描述BUG
  • ubuntu22.04 安装 SecureCRT8.7.3
  • 5.0.7 TabControl的使用
  • Java+Playwright自动化-2-环境准备与搭建-基于Maven
  • ViewModel
  • 设计模式系列(06):抽象工厂模式(Abstract Factory)
  • Vue组件化
  • 用AxumStatusCode细化Rust Web标准格式响应
  • [Vue]浅浅了解vue3响应式的基本原理
  • Jenkins实践(9):pipeline构建历史展示包名和各阶段间传递参数
  • 使用 scikit-learn 库对乌克兰冲突事件数据集进行多维度分类分析
  • MATLAB实现音频参数均衡器(PEQ)
  • 麒麟系统 Linux(aarch64处理器)系统java项目接入海康SDK问题
  • mediapipe标注视频姿态关键点
  • JavaScript 中 this 指向详解
  • 力扣四道题,力扣LCR 016无重复字符的最长子串力扣452.用最小数量的箭引爆气球LCR026.重排链表力扣.1765地图中的最高点
  • 分布式项目保证消息幂等性的常见策略
  • 视频监控汇聚平台EasyCVR工业与安全监控:防爆摄像机的安全应用与注意事项