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:"…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...

MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...

ESP32读取DHT11温湿度数据
芯片:ESP32 环境:Arduino 一、安装DHT11传感器库 红框的库,别安装错了 二、代码 注意,DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...