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

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语言中的函数指针数组吗&#xff1f; 我们通过函数指针数组实现一个&#xff0c;图书管理系统的界面&#xff1a; #include <stdio.h> void doShowAllB…...

Linux学习之路 -- 文件 -- 文件描述符

前面介绍了与文件相关的各种操作&#xff0c;其中的各个接口都离不开一个整数&#xff0c;那就是文件描述符&#xff0c;本文将介绍文件描述符的一些相关知识。 目录 <1>现象 <2>原理 文件fd的分配规则和利用规则实现重定向 <1>现象 我们可以先通过prin…...

JDK动态代理和Cglib动态代理区别

1.如果目标类实现了接口&#xff0c;将会使用JDK动态代理&#xff0c;否则会使用Cglib动态代理; 2.JDK代理使用自己的字节码生成工具生成代理对象&#xff0c;而Cglib会使用ASM字节码生成工具去生成; 3.JDK动态代理是通过反射的方式去实现代理对象的所有方法&#xff0c;通过…...

牛客 | 字符金字塔

请打印输出一个字符金字塔&#xff0c;字符金字塔的特征请参考样例 #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 年代的电脑&#xff0c;每次只能运行一个程序 A programmer would write one at…...

用js代码实现贪吃蛇小游戏

js已经学了大部分了&#xff0c;现在就利用我所学的js知识试试做贪吃蛇小游戏吧 以下部分相关图片以及思路笔记均出自渡一陈老师的视频 首先制作简单的静态页面&#xff0c;添加贪吃蛇移动的背景和相关图片&#xff0c;比如开始游戏等等 将各个功能均封装在函数中&#xff0…...

微信小程序+esp8266温湿度读取

本文主要使用微信小程序显示ESP8266读取的温湿度并通过微信小程序控制LED灯。小程序界面如下图所示 原理讲解 esp8266 通过mqtt发布消息,微信小程序通过mqtt 订阅消息,小程序订阅后,就可以实时收到esp8266 传输来的消息。 个人可免费注册五个微信小程序账号,在微信小程序官…...

软考中级-软件设计师(十)网络与信息安全基础知识

一、网络概述 1.1计算机网络的概念 计算机网络的发展&#xff1a;具有通信功能的单机系统->具有通信功能的多机系统->以共享资源为目的的计算机网络->以局域网及因特网为支撑环境的分布式计算机系统 计算机网络的功能&#xff1a;数据通信、资源共享、负载均衡、高…...

推荐一个好用的命令行工具ShellGPT

ShellGPT 配置安装常用功能聊天写命令并执行 高级功能函数调用角色管理 总结 这两天突然想到&#xff0c;现有的很多工具都在被大模型重构&#xff0c;比如诞生了像perplexity.ai 这种新交互形式的搜索引擎&#xff0c;就连wps也推出了AI服务&#xff0c;甚至都可以直接生成ppt…...

Prompt提示词教程 | 提示工程指南 | 提示词示例 入门篇

在上一节中&#xff0c;我们介绍并给出了如何赋能大语言模型的基本示例。如果还没看而且是刚入门的同学建议看下&#xff0c;有个基本概念。 Prompt提示词教程 | 提示工程指南 | 提示工程简介https://blog.csdn.net/HRG520JN/article/details/138523705在本节中&#xff0c;我…...

uniapp + uView动态表单校验

项目需求&#xff1a;动态循环表单&#xff0c;并实现动态表单校验 页面&#xff1a; <u--form label-position"top" :model"tmForm" ref"tmForm" label-width"0px" :rulesrules><div v-for"(element, index) in tmForm…...

【Linux】HTTPS

欢迎来到Cefler的博客&#x1f601; &#x1f54c;博客主页&#xff1a;折纸花满衣 &#x1f3e0;个人专栏&#xff1a;Linux 目录 &#x1f449;&#x1f3fb;HTTPS协议概念&#x1f449;&#x1f3fb;加密为什么要进行加密 &#x1f449;&#x1f3fb;常见的加密方式对称加密…...

语音识别--使用YAMNet识别环境音

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…...

前端JS必用工具【js-tool-big-box】,邮箱,手机,身份证号,ip地址等正则验证方法学习

这一小节&#xff0c;我们针对前端npm包 js-tool-big-box 的使用做一些讲解&#xff0c;主要是针对项目中&#xff0c;邮箱&#xff0c;手机号&#xff0c;身份证号&#xff0c;ip地址&#xff0c;url格式&#xff0c;邮政编码等验证的方法使用。 目录 1 安装和引入 2 邮箱验…...

notepad++安装 hex-editor插件

打开notepad 点击插件 搜索 hex-editor,点击右侧 安装install 安装成功后&#xff0c;在已安装插件中就有显示了...

Ubuntu18.04设置SSH密钥登录

我们一般使用 VSCode 、MobaXterm、PuTTY等 SSH 客户端来远程管理 Linux 服务器。但是&#xff0c;一般的密码方式登录&#xff0c;容易有密码被暴力破解的问题。所以&#xff0c;一般我们会将 SSH 的端口设置为默认的 22 以外的端口&#xff0c;或者禁用 root 账户登录。但是即…...

自动化运维管理工具----------Ansible模块详细解读

目录 一、自动化运维工具有哪些&#xff1f; 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 &#xff0c;找出 candidates 中所有…...

实验15 MVC

二、实验项目内容&#xff08;实验题目&#xff09; 编写代码&#xff0c;掌握MVC的用法。 三、源代码以及执行结果截图&#xff1a; inputMenu.jsp&#xff1a; <% page contentType"text/html" %> <% page pageEncoding "utf-8" %> &…...

《Python编程从入门到实践》day21

# 昨日知识点回顾 设置背景颜色 在屏幕中央绘制飞船 # 今日知识点学习 12.5 重构&#xff1a;方法_check_events()和_update_screen() 12.5.1 方法_check_events() import sys import pygame from Settings import Settings from Ship import Shipclass AlienInvasion:"…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

1688商品列表API与其他数据源的对接思路

将1688商品列表API与其他数据源对接时&#xff0c;需结合业务场景设计数据流转链路&#xff0c;重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点&#xff1a; 一、核心对接场景与目标 商品数据同步 场景&#xff1a;将1688商品信息…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...

html-<abbr> 缩写或首字母缩略词

定义与作用 <abbr> 标签用于表示缩写或首字母缩略词&#xff0c;它可以帮助用户更好地理解缩写的含义&#xff0c;尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时&#xff0c;会显示一个提示框。 示例&#x…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...