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