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

std::functional 类是干什么用的?


author: hjjdebug
date: 2025年 04月 29日 星期二 15:54:53 CST
description: std::functional 类是干什么用的?


文章目录

  • 1.functional 对象的概念
  • 2.functional 对象存在的意义
    • 2.1 为什么要把接口再封一层?
    • 2.2 c++中函数参数可以不用回调函数, 而改用functional 对象,统一接口
  • 3 补充: std::bind 的作用是什么?

尽量用直白的语言来描述问题,少用那些含混不清的貌似高大上的词汇.

1.functional 对象的概念

std::functional 是c++11引入的类, 为的是通过对象封装一个函数调用
例如. 封装一个普通函数, 封装一个匿名函数, 或者封装一个类的成员函数.

这里所谓的封装,就是包起来,由它保管.
因为在functional 成员中定义了一个函数指针,
由它保留了构建对象时传入的函数地址.
对于类函数,它还保留了由std::bind 传入的对象地址,
当你调用functional 对象时是加了(), 显然,functional类也重载了操作符(),
该操作符会调用保留的地址, 也能够为调用函数添加额外参数,如果你用std::bind绑定过.

给一个简单的例子,其使用估计也就差不多了, 调试完了就有概念了.

#include <iostream>
#include <functional>  //c++11引入的概念//统一接口调用: 通过 std::function 封装不同可调用对象,
//std::function<返回类型(参数类型1,参数类型2,....)>func;using namespace std;
int foo(int x) { return x; }class MyClass {
public://类的成员函数int sum_val(int x) { sum+=x; return sum; }//类的静态函数,用static 来声明,属于类而不属于对象static int s_getval() { return s_val;}
private:int sum;
public:static int s_val;
};
MyClass obj;
int MyClass::s_val=100;int main()
{//封装一个已定义的函数//声明了一个对象,用函数地址为其赋值 , 会调用std::function的赋值构造函数std::function<int(int)> func1 = foo; cout<<"ordinary function ret:"<<func1(5)<<endl;// 封装一个匿名函数(lambda 表达式),直接定义函数体而且不用起名字.// 懒得起名字了,就用[]代替,叫无名.std::function<int(int,int)> func2 = [](int a, int b){return a+b;};cout<<"anonymous func return val:"<<func2(3,5)<<endl;//封装一个静态成员函数,就是封装一个普通函数std::function<int()> func3 = MyClass::s_getval;  cout<<"class static function is as ordinary function:"<<func3()<<endl;//成员函数,需通过 std::bind 传递this 指针为第一个参数std::function<int(int)> func4 = std::bind(&MyClass::sum_val,&obj,std::placeholders::_1);  //_1表示占位符,调用时传递的参数int val=func4(5);val=func4(4);cout << "class function return val:"<<val<<endl;
}

执行代码:

./function
ordinary function ret:5
anonymous func return val:8
class static function is as ordinary function:100
class function return val:9

2.functional 对象存在的意义

2.1 为什么要把接口再封一层?

问题来了, 我直接调用就可以了,为什么还要把它封装起来呢?
好处是. 接口统一. 都是创建对象func,付给其地址,调用对象,
像下面这样func(参数1,参数2,…)
对象重载了()操作符

看起来,不过就是换了个名称而已,能叫好处吗?
嗯, 在普通的函数调用中确实是多此一举. 但在回调函数中有用.
因为回调函数是做为参数传递的函数.
当你写底层代码时, 可能需要调用高层代码,但现在高层代码还没有实现,是什么样子还不清楚.
但是框架必需要确定,传递什么参数,返回什么类型. 这就是回调函数的核心思想.

2.2 c++中函数参数可以不用回调函数, 而改用functional 对象,统一接口

到了c++时代,不用调用回调函数了, 可以用functional 对象了. 你想让系统执行你的代码,
向functional对象传递地址就可以了.
底层代码编写时,虽然不知道上层回调要实现什么功能, 但functonal 对象是知道的,所以它可以完成底层的逻辑.
对底层而言,就是统一了编程接口.
再给一个实例吧. 短小精悍!, 运用了for_each语句, 匿名函数,回调函数.

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>//定义一个process 函数, 它的一个参数是 function object, 
void process(int value, const std::function<void(int)>& callback) {callback(value); //我们可以直接调用这个 functional obj 对象->callback
}int main() {std::vector<int> values = {1, 2, 3, 4, 5};// 使用匿名函数作为for_each的处理函数,其中会调用process 函数//process函数的第二个参数又是一个匿名函数. 它的功能是打印变量的值std::for_each(values.begin(), values.end(), [&](int value) {process(value, [](int x) { std::cout << "Processed: " << x << std::endl; });});return 0;
}

执行结果:

./function
Processed: 1
Processed: 2
Processed: 3
Processed: 4
Processed: 5

for_each是C++标准模板库(STL)中的通用算法,定义于头文件中。
其核心功能是遍历指定迭代器范围内的元素,
并对每个元素执行用户定义的操作。该操作可以是普通函数、函数对象(仿函数)或Lambda表达式

总之, 原来是自己直接调用函数,现在是先创建对象,交给对象一些东西,让对象去调用.
基本上,还是觉得多此一举. 当然,有了这个第三者,这个第三者在安全性上会做一些工作.

不过c++擅长的也就是封装,封装,封装…其三大主流特征之首就是封装. 核心思想是交给我,我替你办! 实际是交给对象,让对象去办.@搞砸了,那是对象的事@,当然也可能是调用的事,匹配的事.

3 补充: std::bind 的作用是什么?

std::bind 是保留传来的参数到std::func 对象,将来调用func对象时, 把这个参数传递出去.
std::bind 调用成员函数, 传递this 指针,只是它的一个应用方式,它可以传递任何自定义数据.

$ cat main.cpp 
#include <iostream>
#include <functional>
#include <string>void printString(const std::string& prefix, const std::string& str) {std::cout << prefix << ": " << str << std::endl;
}int main() {// 创建一个std::function对象,保留一个调用参数到func对象中, 则对象会把参数传递给函数std::function<void(std::string)> boundFunc = std::bind(printString, "Info", std::placeholders::_1);boundFunc("Hello World");  // 输出: Info: Hello Worldreturn 0;
}

执行代码:

./function
Info: Hello World

http://www.xdnf.cn/news/2966.html

相关文章:

  • 项目实战-飞机大战【补档】
  • 【AI面试准备】模型自动化评估
  • C++学习:六个月从基础到就业——异常处理:机制与最佳实践
  • Qt5与现代OpenGL学习(三)纹理
  • 极狐GitLab 如何使用文件导出迁移项目和群组?
  • 机器学习day4-Knn+交叉验证api练习(预测facebook签到位置)
  • QT6链接mysql数据库
  • SQL实战:04之SQL中的分组问题求解
  • 深度学习·经典模型·VisionTransformer
  • 串口通信协议
  • (004)Excel 监视窗口
  • 系统分析师-第十三、十四章
  • 算法设计:分支限界法的基础原理与应用
  • Element:Cheack多选勾选效果逻辑判断
  • 区块链最佳框架:Truffle vs Hardhat vs Brownie
  • partition_pdf 和chunk_by_title 的区别
  • package.json文件中的 ^ 和 ~
  • DOM 事件的处理通常分为三个阶段:捕获、目标、冒泡【前端示例】
  • 京东关键词与商品详情信息数据采集接口指南
  • python jupyter notebook
  • 如何搭建一个简单的文件服务器的方法
  • JavaScript学习教程,从入门到精通,jQuery快速入门指南(30)
  • 建立对人工智能(AI)的信任
  • Oracle11g——空表无法导出的问题
  • 软件分析师-第三遍-章节导图-13/14
  • 基础排序方法
  • 【C++11】新的类功能、lambda
  • SICAR 标准功能块 FB3352 (MODE)工作模式功能块
  • 是否想要一个桌面哆啦A梦的宠物
  • 特征工程四-2:使用GridSearchCV 进行超参数网格搜索(Hyperparameter Tuning)的用途