深入理解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)压电式蜂鸣器,它主要由多谐的一个增胀器…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
