C++第四十五弹---深入理解包装器:提升代码复用性与安全性的利器

article/2025/8/15 23:01:37

 ✨个人主页: 熬夜学编程的小林

💗系列专栏: 【C语言详解】 【数据结构详解】【C++详解】

目录

1 包装器

1.1、function包装器

1.2、bind


1 包装器


1.1、function包装器


function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。那么我们来看看,我们为什么需要function呢?

先看一句代码!!!

auto ret = func(x);

上面func可能是什么呢?那么func可能是函数名函数指针函数对象(仿函数对象)?也有可能是lambda表达式对象?所以这些都是可调用的类型!如此丰富的类型,可能会导致模板的效率低下!为什么呢?我们继续往下看。

代码演示

// 函数模板
template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}
// 普通函数
double f(double i)
{return i / 2;
}
// 仿函数
struct Functor
{double operator()(double d){return d / 3;}
};
int main()
{// 函数名cout << useF(f, 11.11) << endl;// 函数对象cout << useF(Functor(), 11.11) << endl;// lamber表达式cout << useF([](double d)->double { return d / 4; }, 11.11) << endl;return 0;
}

运行结果

通过上面的程序验证,我们会发现useF函数模板实例化了三份,因为count的三个地址都不一样。 

包装器可以很好的解决上面的问题!!!

function原型

std::function在头文件<functional>
// 类模板原型如下
template <class T> function;     // undefined
template <class Ret, class... Args>
class function<Ret(Args...)>;
模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

代码演示

template<class F, class T>
T useF(F f, T x)
{static int count = 0;cout << "count:" << ++count << endl;cout << "count:" << &count << endl;return f(x);
}double f(double i)
{return i / 2;
}
struct Functor
{double operator()(double d){return d / 3;}
};int main()
{// 普通函数std::function<double(double)> func1 = f;cout << useF(func1, 11.11) << endl;// 函数对象std::function<double(double)> func2 = Functor();cout << useF(func2, 11.11) << endl;// lamber表达式std::function<double(double)> func3 = [](double d)->double { return d /4; };cout << useF(func3, 11.11) << endl;return 0;
}

运行结果 

通过上面的程序验证,我们会发现useF函数模板只实例化了一份,因为count的三个地址都相同。  

包装成员函数指针

代码演示

class Plus
{
public:// 静态成员函数,没有this指针static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a + b;}
};
int main()
{function<int(int, int)> f1 = &Plus::plusi;cout << f1(1, 2) << endl;// 有三个参数function<double(Plus*,double, double)> f2 = &Plus::plusd;Plus plus;cout << f2(&plus, 1.1, 2.2) << endl;// 不能显示传this指针,因此语法层面只要类型匹配即可function<double(Plus, double, double)> f3 = &Plus::plusd;cout << f3(Plus(), 1.1, 2.2) << endl;return 0;
}

运行结果

 

1.2、bind


std::bind函数定义在#include<functional>头文件中,是一个函数模板,它就像一个函数包装器(适配器),接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。一般而言,我们用它可以把一个原本接收N个参数的函数fn,通过绑定一些参数,返回一个接收M个(M可以大于N,但这么做没什么意义)参数的新函数。同时,使用std::bind函数还可以实现参数顺序调整等操作。

bind原型

// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);
// with return type (2)
template <class Ret, class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。
调用bind的一般形式:auto newCallable = bind(callable,arg_list);
其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。
arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

代码演示一

int Sub(int a,int b)
{return a - b;
}int main()
{auto f1 = Sub;cout << f1(10, 5) << endl;// 调整两个参数顺序auto f2 = bind(Sub, placeholders::_2, placeholders::_1);cout << f2(10, 5) << endl;cout << typeid(f1).name() << endl;cout << typeid(f2).name() << endl;return 0;
}

运行结果 

代码分析 

代码演示二

class Sub
{
public:int sub(int a, int b){return a - b;}
};int main()
{// 调整参数个数,原本三个参数,加上this指针,第一个参数用匿名对象auto f4 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);cout << f4(10, 5) << endl;Sub sub;// 第一个参数用对象地址auto f5 = bind(&Sub::sub, &sub, placeholders::_1, placeholders::_2);cout << f5(10, 5) << endl;return 0;
}

运行结果

代码演示三

void fx(const string& name, int x, int y)
{cout << name << "-> [血量:" << x << ",蓝:" << y << ']' << endl;
}
int main()
{fx("王昭君", 80, 30);fx("王昭君", 77, 20);fx("王昭君", 60, 0);fx("王昭君", 30, 40);fx("亚瑟", 90, 20);fx("亚瑟", 77, 15);fx("亚瑟", 40, 0);fx("亚瑟", 2, 20);return 0;
}

 运行结果

从代码三我们能够打印一个英雄的属性,但是调用同一个名字太冗余,可以绑定名字。

代码三优化

int main()
{// 绑定名字auto f6 = bind(fx, "王昭君", placeholders::_1, placeholders::_2);f6(80, 30);f6(77, 20);f6(60, 0);f6(30, 40);auto f7 = bind(fx, "亚瑟", placeholders::_1, placeholders::_2);f7(90, 20);f7(77, 15);f7(40, 0);f7(2, 20);return 0;
}

运行结果 

除了绑定第一个参数我们还可以绑定中间的参数,比如我们可以将血量绑定成80,代码如下: 

代码演示四

int main()
{// 绑定血量auto f8 = bind(fx, placeholders::_1, 80, placeholders::_2);f8("武则天", 12);f8("妲己", 33);return 0;
}

运行结果

代码演示四也可以使用 包装器 + 绑定。 

// 包装器 + 绑定
function<void(std::string,int)> f8 = bind(fx, placeholders::_1, 80, placeholders::_2);


http://www.hkcw.cn/article/CZpyFEtMRl.shtml

相关文章

【Java 学习】详细讲解---包和导包、Scanner类、输入源

1. 包 1.1 什么是包&#xff1f; 举个例子&#xff0c;你和你的同学有不同的家庭&#xff0c;你们都有自己的爸爸妈妈&#xff0c;都有自己的家。在自己的家中你们可以按照自己爱好摆放东西&#xff0c;都互不干扰。但是&#xff0c;假如你们的家都在一起&#xff0c;你们就不…

LEfSe分析:R语言一句代码轻松实现

数据和代码获取&#xff1a;请查看主页个人信息&#xff01;&#xff01;&#xff01; 大家好&#xff0c;今天我将介绍如何使用R语言进行LEfSe&#xff08;Linear discriminant analysis Effect Size&#xff09;分析及可视化。LEfSe是一种基于线性判别分析的算法&#xff0c;…

马斯克遭白宫背刺 提名撤销引失望

刚走一天就遭白宫“背刺”,马斯克对此表示失望。2023年10月11日,美国国家航空航天局在休斯敦约翰逊航天中心首次向公众展示了从小行星贝努采集到的样本图片和视频。5月31日,美国白宫宣布撤销对富豪贾里德艾萨克曼出任下一任NASA局长的提名。据报道,艾萨克曼与企业家马斯克关…

双腿戴假肢男子4小时登顶泰山 毅力与自信的见证

5月31日上午,山东泰安泰山景区天气晴朗。一位双腿安装假肢的男士一手拄着拐杖一手抓住扶手向上攀登的场景被游客上传到社交媒体,引发网友热议。6月1日下午,当事人盛先生介绍,这是他第三次登泰山了,从中天门到南天门花费了约4个小时。盛先生说,今年端午假期前,他出差来到…

南京大学通报施工方偷窃学生物品 施工单位被罚违约金

5月29日,南京大学基本建设处发布了一份关于对南京诚善科技有限公司执行合同违约金的通报。通报指出,南京诚善科技有限公司员工于5月13日在学校宿舍楼内偷窃学生物品。根据施工合同相关规定并经处办公会研究确认,南京大学基本建设处决定对该公司执行2000元违约金,从工程款中…

为省30块钱 卡车司机在青海缺氧离世 爱心卡友千里送别

46岁的河南卡车司机常志荣在青藏线因高原缺氧离世。今天上午,多名爱心卡友跨越2400多公里,将他的骨灰及车辆从五道梁地区送回老家安阳林州。5月27日,常志荣在青藏线五道梁地区遭遇严重缺氧不幸去世。车友任先生透露,出发前同行曾建议他至少携带两罐氧气,但他为了节省30元费…

樊振东将改变德国联赛竞争格局 新援加盟引关注

北京时间6月1日,德甲萨尔布吕肯俱乐部宣布中国运动员樊振东加盟该俱乐部,将参与2025-2026赛季德国乒乓球甲级联赛和欧洲冠军联赛。这并不意味着国内赛场上看不到樊振东的身影。目前樊振东仍处在奥运后的调整期,计划通过全国比赛以及国内外俱乐部比赛逐步恢复运动状态。樊振东…

少写一点,发布快一点:2025年的前端极简主义

我们先直白点&#xff1a;你大概并不需要那些 Button.js、PrimaryButton.js、OutlinePrimaryButton.js 甚至 MaybeIfItsFridayButton.js。 在2025年&#xff0c;我们被过度抽象的组件库淹没了——原子设计、过度工程化的 UI 库。 现在&#xff0c;该是我们聊聊「反潮流」的前端…

聊一聊接口测试中耗时请求如何合理安排?

目录 一、异步处理与轮询机制 轮询检查机制 二、 并行化测试执行 三、模拟与桩技术&#xff08;Mock/Stub&#xff09; 四、动态超时与重试策略 五、测试架构设计优化 分层测试策略 并行化执行 网络优化 六、测试用例分层管理 金字塔策略 七、 缓存与数据复用 响应…

VMware没有虚拟网卡,VMnet1,VMnet8显示黄色三角警告

VMware安装后没有虚拟网卡&#xff0c;VMnet1&#xff0c;VMnet8显示黄色三角警告 VMware安装后没有虚拟网卡&#xff0c;VMnet1&#xff0c;VMnet8显示黄色三角警告 VMware安装后没有虚拟网卡&#xff0c;VMnet1&#xff0c;VMnet8显示黄色三角警告 问题描述&#xff1a; 主机…

情侣和一家三口在迪士尼打架 因拍照起冲突

5月31日,有网友发布视频称,在上海迪士尼有一对情侣和一家三口发生了冲突,此事引发了广泛关注。视频中可以看到,双方在现场扭打,周围的人纷纷上前劝阻。据权威人士透露,事件发生在5月31日,地点并不是排队区域,而是游客自由打卡拍照的地方。情侣和一家三口因拍照问题产生…

猎德村龙舟文化与其他地区区别是什么 翻船事件引关注

端午节对于很多人来说只是一个普通的假期,但对于广东人来说却意义非凡。因为在这一天,他们要举行紧张刺激的龙舟比赛。猎德村在以往的比赛中总是表现亮眼,但今年还没正式开始就闹出了大笑话。三条新龙舟中有两条翻了,隔壁村因此疯狂嘲笑他们。网友们得知龙舟翻船的原因竟与…

未来3天可能有地磁暴 或现红绿极光

6月1日,中国气象局国家空间天气监测预警中心发布消息,北京时间5月31日7时45分左右,太阳活动区14100开始爆发耀斑,软X射线流量迅速上升,并在8时05分达到M8.1级中等耀斑强度。预计未来三天可能发生地磁暴,6月2日左右我国北部地区有机会出现较为明显的极光,部分地区甚至可能…

莎拉称不优先考虑与马科斯和解谈判 民众与国家更重要

综合菲律宾《马尼拉标准报》等媒体报道,菲律宾副总统莎拉杜特尔特表示,她不优先考虑与总统马科斯进行和解谈判。莎拉认为,目前不应谈论和解,因为个人问题并不重要,更重要的是民众与国家的利益。此前,据路透社等媒体5月19日报道,马科斯在社交媒体上分享了一期播客,表达了…

肖战主演的《藏海传》在台湾被刷屏 两岸文化共鸣引发热议

正在热播的电视剧《藏海传》在台湾引起了广泛关注,不仅观众好评不断,媒体也争相报道。这部剧以其精良的制作、紧凑的情节和展现的中华文化吸引了大量台湾观众。5月31日,“肖战演藏海在台湾刷屏”成为微博热搜话题。近年来,大陆电视剧在台湾持续走红。专家指出,除了这些作品…

孙中山孙女曾无偿捐赠大批文物 心系家乡贡献卓著

6月1日,孙中山长孙女孙穗瑛的家人为她在加州举办追思会。孙穗瑛于3月24日在美国去世,享年103岁。她和妹妹孙穗华生前都十分关心家乡中山的发展,多次回国探亲,并无偿捐赠大批文物。两人在2016年11月荣获中山市政府授予的“中山市荣誉市民”称号。孙穗瑛出生于1922年1月16日,…

最适合祝福考生的台词出现了 好运加持轻松过关

稳住,你能赢!考的全会,蒙的全对,好运加持,轻松过关。放轻松,努力就是最好的答案。笔下如有神,运气爆棚时,祝你考场开挂,惊喜连连!深呼吸,慢慢来,你比想象中强大。考的题目都眼熟,选的答案都正确,好运来敲门啦!笔下生花,未来可期。幸运小星星,统统落你卷子上,…

和院士一起科学过六一 科普短视频点燃好奇心

2025年六一国际儿童节来临之际,中国儿童中心联合抖音邀请多位中国工程院院士和中国科学院院士,针对青少年儿童关心的趣味学科知识进行解答分享。这些内容被汇总到“院士答青少年问”专题页,方便家长和孩子们查阅浏览。5月26日,火山地质学家刘嘉麒院士和遥感学家童庆禧院士来…

普京为何重提“中俄印”三角 重启对话时机成熟?

普京政府希望尽早重启中俄印大三角机制,呼吁中印尽快给出答复。俄罗斯外长拉夫罗夫公开表示,鉴于中印在实控线问题上已达成谅解,恢复三方对话机制的时机已经成熟。俄罗斯对中俄印三边机制非常重视,认为这可以与自己力推的“向东看”战略相辅相成。此前,中俄印三方已召开过…

2022---不重复版的数的划分-且范围太大

1.数的划分--数的划分--dfs剪枝-CSDN博客 2.范围太大&#xff0c;这题用dp 3.状态转移公式其中1是泛指 #include<bits/stdc.h> using namespace std; #define N 100011 typedef long long ll; typedef pair<int,int> pii; ll dp[2025][12]; int n,k; void solv…