当前位置: 首页 > 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:"…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

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

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

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

ETLCloud可能遇到的问题有哪些?常见坑位解析

数据集成平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;Extract&#xff09;、转换&#xff08;Transform&#xff09;和加载&#xff08;Load&#xff09;过程。提供了一个简洁直观的界面&#xff0c;以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...