深入理解C++ 中的可调⽤对象
C++中的可调⽤对象总结
- 普通函数
- 类成员函数
- 类静态成员函数
- 与类成员函数的区别
- 仿函数
- 简单示例
- 高级用法-状态保持
- 优缺点
- 优点
- 缺点
- 函数指针
- 获取函数地址
- 声明并调用函数指针
- lambda表达式
- 语法定义
- 捕获
- 单个捕获符
- std::function()
- 协程
可调用对象用处⼴泛:
- ⽐如在使⽤⼀些基于范围的模板函数时,如
sort(It first, It last, Compare cmp)、all_of()、find_if()等),需要传⼊⼀个可调⽤对象客制化处理。 - 在处理⼀些回调函数、触发函数时,也会使⽤可调⽤对象。
满足以下条件的为可调用对象:
- 是一个函数或类成员函数
- 是一个函数指针
- 是一个重载operator()的类对象
- lambda表达式
- 是一个可转型为函数指针的类对象
- 是一个类成员函数指针
- bind表达式、std::function()
- 协程
普通函数
int add(int a, int b) {return a + b;
}
int main() {int num1, num2;std::cout << "Enter two numbers: ";std::cin >> num1 >> num2;int sum = add(num1, num2);std::cout << "The sum of " << num1 << " and " << num2 << " is: " << sum << s << "\n";return 0;
}
类成员函数
#include <iostream>
using namespace std;
class Box{
public:double length; // ⻓度double breadth; // 宽度double height; // ⾼度// 成员函数声明double getVolume(void);void setLength( double len );void setBreadth( double bre );void setHeight( double hei );
};
// 成员函数定义
double Box::getVolume(void)
{return length * breadth * height;
}
void Box::setLength( double len )
{length = len;
}
void Box::setBreadth( double bre )
{breadth = bre;
}
void Box::setHeight( double hei )
{height = hei;
}
int main( )
{Box box; // 声明 box,类型为 Boxdouble volume = 0.0; // ⽤于存储体积// 详述box.setLength(6.0);box.setBreadth(7.0);box.setHeight(5.0);// 体积volume = box.getVolume();cout << "box 的体积:" << volume <<endl;return 0;
}
类静态成员函数
类中的静态成员函数作⽤在整个类的内部,类静态成员函数属于类而非对象。静态成员函数只能访问对应类内部的静态数据成员(因为静态成员函数没有this指针)。类的static函数在类内声明、类外定义时,类内使用static修饰,类外则不能加static关键字,否则会出现编译错误。
class Box{
private:int _non_static;static int _static;
public:int a(){return _non_static;}static int b(){//_non_static=0; 错误//静态成员函数不能访问⾮静态成员变量return _static;}static int f(){//a(); (不对,静态成员函数不能访问⾮静态成员函数)return b();}
};int Box::_static= 0;// static静态成员变量可以在类的外部修改int main(){Box box;Box* pointer=&box;box.a();pointer->a();Box::b(); // 类名::静态成员函数名return 0;
}
与类成员函数的区别
- 静态成员函数没有
this指针,只能访问静态成员(包括静态成员变量和静态成员函数)。 - 普通成员函数有
this指针,可以访问类中的任意成员;⽽静态成员函数没有this指针。
仿函数
仿函数就是重载了()运算符的类对象,函数功能通过重载()实现。(⾏为类似函数,故称仿函数)。实际上就是创建⼀个类,该类重载了()运算符,使得类的实例可以像函数⼀样被调⽤。这允许你在函数对象内部保存状态,并在调⽤时执⾏操作。
简单示例
class Foo
{void operator()(){cout << __FUNCTION__ << endl;}
};
int main()
{Foo a;//定义对象调⽤a.operator()();//直接通过对象调⽤a();//通过临时对象调⽤Foo()();
}
高级用法-状态保持
仿函数可以具有成员变量,因此在多次调用之间可以保持状态。这在算法需要记录或更新某些值的情况下非常有用。
考虑一个例子:对一个
vector统计长度小于5的string的个数
优缺点
优点
- 状态保持:仿函数可以具有成员变量,因此在多次调用之间可以保持状态。
- 更灵活的接口设计:仿函数可以根据需要定制接口,以适应特定的算法或场景。例如,可以根据算法需要添加额外的成员函数或数据成员。
- 更好的封装:仿函数可以将数据和操作封装在一个单独的对象中,这有助于实现更清晰、更模块化的代码。
-
缺点
- 需要单独实现一个类
函数指针
与数据项相似,函数也有地址。函数的地址就是存储它的机器语⾔代码内存的开始地址。通常情况下,这些地址对⽤⼾⽽⾔并不重要,但对于程序⽽⾔,却很有⽤。⽐⽅说,可以编写将另⼀个函数的地址作为参数的函数,这样第⼀个函数就能够找到第⼆个函数,并运⾏它。与直接调⽤另⼀个函数相⽐,这种⽅法虽然很笨拙,但是它允许在不同的时间传递不同函数的地址,这也就意味着可以在不同的时间使⽤不同的函数。
获取函数地址
函数名,不加()
声明并调用函数指针
使用using而非old style声明函数指针!
注意两种方式绑定函数的区别!
- 使用 using 声明函数指针
#include<iostream>int add(int a, int b) {return a + b;
}int main() {// 使用 using 声明函数指针类型using AddFunctionPtr = int (*)(int, int);// 创建函数指针变量并指向 add 函数AddFunctionPtr my_add_function = &add;// 使用函数指针调用 add 函数int result = my_add_function(3, 4);return 0;
}
- old style
#include<iostream>int add(int a, int b) {return a + b;
}int main() {// 使用 old style 声明函数指针int (*my_add_function )(int, int);// 指向 add 函数my_add_function = &add;// 使用函数指针调用 add 函数int result = my_add_function(3, 4);// int result = (*my_add_function)(3, 4); // okreturn 0;
}
lambda表达式
Lambda表达式是Modern C++的⼀个语法糖 。 Lambda表达式用于构造闭包:能够捕获作用域中的变量的无名函数对象。
语法定义
- 没有显式模板形参的 lambda 表达式(可以不泛型)
[捕获列表] [前属性] [形参列表] [说明符] [异常] [后属性] [返回类型] [约束] [函数体]
[capture list] front-attr(opt) (params) specs(opt) exception(opt) back-attr(opt) railing-type(opt) requires(opt) {body}
- 有显式模板形参的 lambda 表达式(必然泛型)(C++20起)
捕获
捕获 是一个含有>=0个捕获符 的逗号分隔列表,可以默认捕获符 开始。捕获列表定义了可以从 lambda 函数体之内访问的外部变量。默认捕获符只有&(按引用) 和 =(按复制),它们都将隐式捕获被使用的自动存储期变量(函数能看到的任一变量)。
注意:以默认捕获符隐式捕获的当前对象(*this),将始终按引用捕获,即使默认捕获符是 =。
单个捕获符
- 简单的按复制捕获
- 作为包展开的简单的按复制捕获
- 带初始化器的按复制捕获
- 简单的按引用捕获
- 作为包展开的简单的按引用捕获
- 带初始化器的按引用捕获
- 当前对象的简单的按引用捕获
- 当前对象的简单的按复制捕获
- 初始化器为包展开的按复制捕获
- 初始化器为包展开的按引用捕获
- 不可重复捕获
-
当默认捕获符是 & 时,后继的简单捕获符不能以 & 开始
struct S2 { void f(int i); }; void S2::f(int i) {[&]{}; // OK:默认按引用捕获[&, i]{}; // OK:按引用捕获,但 i 按值捕获[&, &i] {}; // 错误:按引用捕获为默认时的按引用捕获[&, this] {}; // OK:等价于 [&][&, this, i]{}; // OK:等价于 [&, i] } -
当默认捕获符是 = 时,后继的简单捕获符必须以 &、*this (C++17 起)、this (C++20 起) 之一开始。
struct S2 { void f(int i); }; void S2::f(int i) {[=]{}; // OK:默认按复制捕获[=, &i]{}; // OK:按复制捕获,但 i 按引用捕获[=, *this]{}; // C++17 前:错误:无效语法// C++17 起:OK:按复制捕获外围的 S2[=, this] {}; // C++20 前:错误:= 为默认时的 this// C++20 起:OK:同 [=] } -
任何捕获符只可以出现一次,并且名字不能与任何形参名相同:
struct S2 { void f(int i); }; void S2::f(int i) {[i, i] {}; // 错误:i 重复[this, *this] {}; // 错误:"this" 重复(C++17)[i] (int i) {}; // 错误:形参和捕获的名字相同 }
-
std::function()
协程
相关文章:
深入理解C++ 中的可调⽤对象
C中的可调⽤对象总结 普通函数类成员函数类静态成员函数与类成员函数的区别 仿函数简单示例高级用法-状态保持优缺点优点缺点 函数指针获取函数地址声明并调用函数指针 lambda表达式语法定义捕获单个捕获符 std::function()协程 可调用对象用处⼴泛: ⽐如在使⽤⼀些…...
汇编程序调用 C 程序详解
文章目录 1. ATPCS 规则 2. 汇编和C程序传递参数 汇编程序向 C 程序的函数传递参数 C 程序返回结果给汇编程序 代码示例 3. C 函数使用栈 4. C 语言中读写寄存器 在嵌入式开发中,经常需要在 C 程序和 ARM 汇编程序之间进行相互调用。为了保证这些调用的正确性…...
代码随想三刷图论篇1
代码随想三刷图论篇1 98. 所有可达路径题目代码99. 岛屿数量题目代码100. 岛屿的最大面积题目代码101. 孤岛的总面积题目代码102. 沉没孤岛题目代码103. 水流问题题目代码98. 所有可达路径 题目 链接 代码 import java.util.*;class Main{public static void main(String […...
Windows 快捷键汇总
Windows 快捷键汇总 前言进阶快捷键【最好用】Chrome 常用快捷键【跟 Windows 快捷键不搭杆,但常用】基础快捷键扩展快捷键 前言 Coder 苦鼠标久已,整理汇总 Windows 快捷键包括一些常用的快捷键,比如“浏览器”相关的快捷键内容分为四小节&…...
微服务有哪些组件?
1.注册中心:用于服务的注册和发现,管理微服务的地址 Nacos,Eureka 2.配置中心:集中管理微服务的配置中心 Nacos config 3.远程调用:用于不同微服务间的通信和协作 RESTful API(RestTemplate࿰…...
camera-qsc-crosstalk校准数据XTALK回写
问题背景 手机越做越紧凑,需要模组和芯片尺寸越做越小,在尺寸一定的基础上,高像素和大像素,对于手机摄像头来说,一直是一对矛盾的存在。 高像素:带来高分辨率画质大像素:带来暗态下高感光度和…...
混合贪心算法求解地铁线路调度
一、问题描述 城市轨道交通的繁荣发展,带来了车辆资源需求的日益增加。如何兼顾运营服务水平和运营成本,以最少的车底优质地完成运输任务成为一大严峻问题。本题在后续的描述中将由多辆动车和拖车组合而成的车组称为车底。在日常的运营组织中࿰…...
vue项目:关闭页面,删除本地登录信息
vue项目:关闭页面,删除本地登录信息 代码 代码 import { removeToken } from /utils/auth //区分关闭和刷新页面,关闭时退出登录 window.onload ()>{if(!window.sessionStorage["tempFlag"]){removeToken();location.reload()…...
获奖案例回顾|基于卫星遥感和无人机的水稻全流程风险减量项目
引言 在现代农业保险领域,技术创新是推动行业进步的关键。珈和科技与太平财险的合作,旨在利用先进的卫星遥感和无人机技术,解决传统农业保险面临的诸多挑战,从而提升保险效率和服务质量。本次分享的项目案例获得了《金融电子化》…...
全栈 Discord 克隆:Next.js 13、React、Socket.io、Prisma、Tailwind、MySQL笔记(一)
前言 阅读本文你需要有 Next.js 基础 React 基础 Prisma 基础 tailwind 基础 MySql基础 准备工作 打开网站 https://ui.shadcn.com/docs 这不是一个组件库。它是可重用组件的集合,您可以将其复制并粘贴到应用中。 打开installation 选择Next.js 也就是此页面…...
【Unity】制作简易计时器
一、创建计时器相关的变量 我们需要创建三个变量,分别是:计时时长、计时剩余时长、是否处于计时状态。 public float duration;//计时时长 public float remain; //计时剩余时长 public bool isCount; //是否处于计时状态 二、初始化变量 我们可以直…...
TDesign组件库日常应用的一些注意事项
【前言】Element(饿了么开源组件库)在国内使用的普及率和覆盖率高于TDesign-vue(腾讯开源组件库),这也导致日常开发遇到组件使用上的疑惑时,网上几乎搜索不到其文章解决方案,只能深挖官方文档或…...
51单片机7(点亮第一个LED)
一、LED简介 1、LED,它是一个发光二极管,它具有单向导电性,那么通过5毫安的一个电流,就可以使它发光,那么电流越大,它的发光也就越强,但是电流不能过大,过大会把这个发光二极管给烧…...
基于Vue和UCharts的前端组件化开发:实现高效、可维护的词云图与进度条组件
基于Vue和UCharts的前端组件化开发:实现高效、可维护的词云图与进度条组件 摘要 随着前端技术的迅速发展和业务场景的日益复杂,传统的整块应用开发方式已无法满足现代开发的需求。组件化开发作为一种有效的解决方案,能够将系统拆分为独立、…...
CentOS 系统监控项
在维护和优化 CentOS 系统时,实时监控硬件和资源的使用情况非常重要。为了满足工作需要,可以定时采集 CentOS 系统相关的监控数据,并将其推送到 Prometheus 进行集中监控和管理。以下是日常采集项及对应的 shell 命令,并附上每项命…...
连锁直营店小程序赋能多店如何管理
如商超便利店卖货线下场景,也有不少品牌以同城多店和多地开店经营为主,获取店铺周围客户和散流,如今线上重要性凸显,品牌电商发展是经营的重要方式之一,也是完善同城和外地客户随时便捷消费的方式之一。 多个门店管理…...
决策树算法入门到精通:全面解析与案例实现
1. 介绍决策树算法 决策树的基本概念和原理 决策树是一种基于树形结构的分类和回归方法,通过对数据集进行递归地划分,每个内部节点表示一个属性上的判断,每个叶节点代表一种类别或者数值。 决策树在机器学习中的应用场景 分类问题…...
LangChain —— 多模态大模型的 prompt template
文章目录 一、如何直接将多模态数据传输给模型二、如何使用 mutimodal prompts 一、如何直接将多模态数据传输给模型 在这里,我们演示了如何将多模式输入直接传递给模型。对于其他的支持多模态输入的模型提供者,langchain 在类中提供了内在逻辑来转化为期…...
ssh升级
文章目录 ssh升级一、解包ssh、ssl二、更新安装ssl三、手动更新手动复制库文件四、创建符号链接五、更新库路径六、验证库文件七、设置库路径环境变量八、配置、编译、安装OpenSSH:意外:缺少 zlib 的开发库解决方法: 九、刷新ssh服务、查看ss…...
51单片机10(蜂鸣器介绍)
一、蜂鸣器介绍: 1、蜂鸣器是一种一体化结构的电子讯响器,采用直流电压供电,广泛应用于电子产品中作为发声器件。蜂鸣器主要分为压电式蜂鸣器和电磁式蜂鸣器。 (1)压电式蜂鸣器,它主要由多谐的一个增胀器…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
医疗AI模型可解释性编程研究:基于SHAP、LIME与Anchor
1 医疗树模型与可解释人工智能基础 医疗领域的人工智能应用正迅速从理论研究转向临床实践,在这一过程中,模型可解释性已成为确保AI系统被医疗专业人员接受和信任的关键因素。基于树模型的集成算法(如RandomForest、XGBoost、LightGBM)因其卓越的预测性能和相对良好的解释性…...
如何把工业通信协议转换成http websocket
1.现状 工业通信协议多数工作在边缘设备上,比如:PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发,当设备上用的是modbus从站时,采集设备数据需要开发modbus主站;当设备上用的是西门子PN协议时…...
Python打卡训练营学习记录Day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
c++算法学习3——深度优先搜索
一、深度优先搜索的核心概念 DFS算法是一种通过递归或栈实现的"一条路走到底"的搜索策略,其核心思想是: 深度优先:从起点出发,选择一个方向探索到底,直到无路可走 回溯机制:遇到死路时返回最近…...
