C++语法|可调用对象与function类型
文章目录
- 引入
- function的使用
- function类型的典型应用
- function类型的原理
- 实现
- 代码优化
- 可变参的函数对象
引入
还记得C语言中的函数指针数组吗?
我们通过函数指针数组实现一个,图书管理系统的界面:
#include <stdio.h>
void doShowAllBooks() {printf("查看所有书籍信息\n");
}
void doBorrow() {printf("借书\n");
}
void doBack() {printf("还书\n");
}
void doQueryBooks() {printf("查询书籍\n");
}
void doLoginOut() {printf("注销\n");
}
int main() {int choice = 0;void (*actionArray[5])() = {doShowAllBooks, doBorrow, doBack, doQueryBooks, doLoginOut};while (1) {printf("----------------\n");printf("1.查看所有书籍信息\n");printf("2.借书\n");printf("3.还书\n");printf("4.查询书籍\n");printf("5.注销\n");printf("----------------\n");printf("请选择: ");scanf("%d", &choice);if (choice < 1 || choice > 5) {printf("输入数字无效,重新选择\n");} else {// 调用相应的函数(*actionArray[choice - 1])();}}return 0;
}
我们通过函数指针数组集中保留了我们的函数,让巧用显得十分方便,那么在C++中,我们也有类似的实现。
function的使用
我觉得function简单一点来理解就是它能够保留可调用对象,
function是一个模板,当我们创建这个模板的时候需要一些额外的信息,所谓的额外信息就是指该function类型能够表示的对象的调用形式:
function<int(int, int)>
表示我们生命里一个function类型,它可以接受两个int、返回一个int的可调用对象。
void hello1() {cout << "hello world!" << endl;
}void hello2(string str) { //void (*pfunc) (string)用函数指针调用cout << str << endl;
}int sum(int a, int b) {return a + b;
}class Test {
public: //成员方法的调用必须依赖一个对象void (Test::*pfunc) (string)void hello(string str) {cout << str << endl; }
};int main () {//从function 的类模板定义处,用一个函数类型实例化functionfunction<void()> func1 = hello1; // func1(hello1)func1(); //func1.operator() ==> hello1()function<void(string)> func2 = hello2;func2("hello hello2"); //dunc2.operator(string str) ==> hello2(str)function<int(int, int)> func3 = sum;cout << func3(1, 1) << endl;//保留函数对象 operator()function<int(int, int)> func4 = [](int a, int b)->int {return a + b; };cout << func4(100, 200) << endl;//对类的成员方法也可以进行保留 hello有两个参数 一个是this指针一个是string strfunction<void(Test*, string str)> func5 = &Test::hello;Test t;//func5(&Test(), "call Test::hello"); 报错,至少clang g++不允许func5(&t, "Call Test::hello");return 0;
}
function类型的典型应用
通过定义map和function类型实现一个读书管理系统。
void doShowAllBooks() { cout << "查看所有书籍信息" << endl; }
void doBorrow() { cout << "借书" << endl; }
void doBack() { cout << "还书" << endl; }
void doQueryBooks() { cout << "查询书籍" << endl; }
void doLoginOut() { cout << "注销" << endl; }int main()
{int choice = 0;// 用C语言的函数指针其实也可以实现这个例子(采用数组来映射函数指针)// 但是他不能实现lambda表达式和函数对象map<int, function<void()>> actionMap;actionMap.insert({1, doShowAllBooks}); // insert(make_pair(xx, xx));actionMap.insert({2, doBorrow});actionMap.insert({3, doBack});actionMap.insert({4, doQueryBooks});actionMap.insert({5, doLoginOut});for (;;){cout << "----------------" << endl;cout << "1.查看所有书籍信息" << endl;cout << "2.借书" << endl;cout << "3.还书" << endl;cout << "4.查询书籍" << endl;cout << "5.注销" << endl;cout << "----------------" << endl;cout << "请选择: ";cin >> choice;auto it = actionMap.find(choice);if (it == actionMap.end()) {cout << "输入数字无效,重新选择" << endl;} else {it->second();}
function类型的原理
通过举例来说明,有如下例子,func1可以打印hello world!
void hello(string str) { cout << str << endl; }
int main () {function<void(string str)> func1(hello); // func1 = hello;func1("hello world");return 0
}
实现
通过分析我们可以知道function我们可以使用模板类来实现它,在这个模板类中,我们需要使用一个函数指针来指向hello函数。然后需要重载函数调用运算符。
- 首先我们需要实现一个通用的模板类
my_function,这个通用模板类不需要任何实现。仅仅让编译器找到匹配的模板类定义
//my_function<void(string)> func1(hello);
template<typename Fty>
class my_function { };
- 实现特例化的模板类
template<typename R, typename A1>
//my_function<void(string)> func1(hello);
class my_function<R(A1)> {
public:using PFUNC = R (*) (A1);my_function(PFUNC pfunc) : _func(pfunc) {}R operator() (A1 arg) const {return _pfunc(arg); } //hello(arg)
private:PFUNC _pfunc;
}
- 调用检验
int main() {my_function<void(string)> func1(hello); // 定义了一个函数对象,类型为void(string)func1("Hello, world!"); // func1.operator()("Hello, world!");return 0;
}
代码优化
如果我们要使用function来保存int sum(int a, int b)呢?我们岂不是又要实现一个特例化的模板类?答案肯定是不用!
void hello(string str) { cout << str << endl; }
int sum(int a, int b) { return a + b; }
int main () {function<void(string)> func1(hello); // func1 = hello;func1("hello world");function<void(int a, int b)> func2(sum);cout << func2(10, 20) << endl;return 0
}
可变参的函数对象
template<typename R, typename... Args> //可变参的类型参数
class my_function<R(Args...)> {
public:using PFUNC = R (*) (Args...);my_function(PFUNC pfunc) : _pfunc(pfunc) {}R operator()(Args... args) const { return _pfunc(args...); } //hello(arg)
private:PFUNC _pfunc;
};
相关文章:
C++语法|可调用对象与function类型
文章目录 引入function的使用function类型的典型应用function类型的原理实现代码优化可变参的函数对象 引入 还记得C语言中的函数指针数组吗? 我们通过函数指针数组实现一个,图书管理系统的界面: #include <stdio.h> void doShowAllB…...
Linux学习之路 -- 文件 -- 文件描述符
前面介绍了与文件相关的各种操作,其中的各个接口都离不开一个整数,那就是文件描述符,本文将介绍文件描述符的一些相关知识。 目录 <1>现象 <2>原理 文件fd的分配规则和利用规则实现重定向 <1>现象 我们可以先通过prin…...
JDK动态代理和Cglib动态代理区别
1.如果目标类实现了接口,将会使用JDK动态代理,否则会使用Cglib动态代理; 2.JDK代理使用自己的字节码生成工具生成代理对象,而Cglib会使用ASM字节码生成工具去生成; 3.JDK动态代理是通过反射的方式去实现代理对象的所有方法,通过…...
牛客 | 字符金字塔
请打印输出一个字符金字塔,字符金字塔的特征请参考样例 #include <stdio.h> #include <string.h> using namespace std; int main() {char c;scanf("%c", &c);for (int i 1; i < (c - 64); i)//第一个循环决定了有多少行{//c:67 第三…...
【计算机科学速成课】笔记三——操作系统
文章目录 18.操作系统问题引出——批处理设备驱动程序多任务处理虚拟内存内存保护Unix 18.操作系统 问题引出—— Computers in the 1940s and early 50s ran one program at a time. 1940,1950 年代的电脑,每次只能运行一个程序 A programmer would write one at…...
用js代码实现贪吃蛇小游戏
js已经学了大部分了,现在就利用我所学的js知识试试做贪吃蛇小游戏吧 以下部分相关图片以及思路笔记均出自渡一陈老师的视频 首先制作简单的静态页面,添加贪吃蛇移动的背景和相关图片,比如开始游戏等等 将各个功能均封装在函数中࿰…...
微信小程序+esp8266温湿度读取
本文主要使用微信小程序显示ESP8266读取的温湿度并通过微信小程序控制LED灯。小程序界面如下图所示 原理讲解 esp8266 通过mqtt发布消息,微信小程序通过mqtt 订阅消息,小程序订阅后,就可以实时收到esp8266 传输来的消息。 个人可免费注册五个微信小程序账号,在微信小程序官…...
软考中级-软件设计师(十)网络与信息安全基础知识
一、网络概述 1.1计算机网络的概念 计算机网络的发展:具有通信功能的单机系统->具有通信功能的多机系统->以共享资源为目的的计算机网络->以局域网及因特网为支撑环境的分布式计算机系统 计算机网络的功能:数据通信、资源共享、负载均衡、高…...
推荐一个好用的命令行工具ShellGPT
ShellGPT 配置安装常用功能聊天写命令并执行 高级功能函数调用角色管理 总结 这两天突然想到,现有的很多工具都在被大模型重构,比如诞生了像perplexity.ai 这种新交互形式的搜索引擎,就连wps也推出了AI服务,甚至都可以直接生成ppt…...
Prompt提示词教程 | 提示工程指南 | 提示词示例 入门篇
在上一节中,我们介绍并给出了如何赋能大语言模型的基本示例。如果还没看而且是刚入门的同学建议看下,有个基本概念。 Prompt提示词教程 | 提示工程指南 | 提示工程简介https://blog.csdn.net/HRG520JN/article/details/138523705在本节中,我…...
uniapp + uView动态表单校验
项目需求:动态循环表单,并实现动态表单校验 页面: <u--form label-position"top" :model"tmForm" ref"tmForm" label-width"0px" :rulesrules><div v-for"(element, index) in tmForm…...
【Linux】HTTPS
欢迎来到Cefler的博客😁 🕌博客主页:折纸花满衣 🏠个人专栏:Linux 目录 👉🏻HTTPS协议概念👉🏻加密为什么要进行加密 👉🏻常见的加密方式对称加密…...
语音识别--使用YAMNet识别环境音
⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计3077字,阅读大概需要3分钟 🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号…...
前端JS必用工具【js-tool-big-box】,邮箱,手机,身份证号,ip地址等正则验证方法学习
这一小节,我们针对前端npm包 js-tool-big-box 的使用做一些讲解,主要是针对项目中,邮箱,手机号,身份证号,ip地址,url格式,邮政编码等验证的方法使用。 目录 1 安装和引入 2 邮箱验…...
notepad++安装 hex-editor插件
打开notepad 点击插件 搜索 hex-editor,点击右侧 安装install 安装成功后,在已安装插件中就有显示了...
Ubuntu18.04设置SSH密钥登录
我们一般使用 VSCode 、MobaXterm、PuTTY等 SSH 客户端来远程管理 Linux 服务器。但是,一般的密码方式登录,容易有密码被暴力破解的问题。所以,一般我们会将 SSH 的端口设置为默认的 22 以外的端口,或者禁用 root 账户登录。但是即…...
自动化运维管理工具----------Ansible模块详细解读
目录 一、自动化运维工具有哪些? 1.1Chef 1.2puppet 1.3Saltstack 二、Ansible介绍 2.1Ansible简介 2.2Ansible特点 2.3Ansible工作原理及流程 2.3.1内部流程 2.3.2外部流程 三、Ansible部署 3.1环境准备 3.2管理端安装 ansible 3.3Ansible相关文件 …...
零基础代码随想录【Day27】|| 39. 组合总和,40.组合总和II, 131.分割回文串
目录 DAY27 39. 组合总和 解题思路&代码 40.组合总和II 解题思路&代码 131.分割回文串 解题思路&代码 DAY27 39. 组合总和 力扣题目链接(opens new window) 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有…...
实验15 MVC
二、实验项目内容(实验题目) 编写代码,掌握MVC的用法。 三、源代码以及执行结果截图: inputMenu.jsp: <% page contentType"text/html" %> <% page pageEncoding "utf-8" %> &…...
《Python编程从入门到实践》day21
# 昨日知识点回顾 设置背景颜色 在屏幕中央绘制飞船 # 今日知识点学习 12.5 重构:方法_check_events()和_update_screen() 12.5.1 方法_check_events() import sys import pygame from Settings import Settings from Ship import Shipclass AlienInvasion:"…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...
Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...
