深入理解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)压电式蜂鸣器,它主要由多谐的一个增胀器…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...