深入理解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声明函数指针!
注意两种方式绑定函数的区别!

  1. 使用 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;
}
  1. 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表达式用于构造闭包:能够捕获作用域中的变量的无名函数对象。

语法定义

  1. 没有显式模板形参的 lambda 表达式(可以不泛型)
  [捕获列表]     [前属性]       [形参列表] [说明符]   [异常]         [后属性]        [返回类型]         [约束]       [函数体]
[capture list] front-attr(opt) (params) specs(opt)exception(opt) back-attr(opt) railing-type(opt) requires(opt) {body}
  1. 有显式模板形参的 lambda 表达式(必然泛型)(C++20起)

捕获

捕获 是一个含有>=0个捕获符 的逗号分隔列表,可以默认捕获符 开始。捕获列表定义了可以从 lambda 函数体之内访问的外部变量。默认捕获符只有&(按引用) 和 =(按复制),它们都将隐式捕获被使用的自动存储期变量(函数能看到的任一变量)。

注意:以默认捕获符隐式捕获的当前对象(*this),将始终按引用捕获,即使默认捕获符是 =

单个捕获符

  1. 简单的按复制捕获
  2. 作为包展开的简单的按复制捕获
  3. 带初始化器的按复制捕获
  4. 简单的按引用捕获
  5. 作为包展开的简单的按引用捕获
  6. 带初始化器的按引用捕获
  7. 当前对象的简单的按引用捕获
  8. 当前对象的简单的按复制捕获
  9. 初始化器为包展开的按复制捕获
  10. 初始化器为包展开的按引用捕获
  • 不可重复捕获
    • 当默认捕获符是 & 时,后继的简单捕获符不能以 & 开始

      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()

协程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/45814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

排序-java(详解)

一&#xff0c;分类 主要的排序大致分为以下几类&#xff1a; 1&#xff0c;插入排序&#xff0c;又分为直接插入排序和希尔排序 2&#xff0c;选择排序&#xff0c;又分为选择排序和堆排序 3&#xff0c;交换排序&#xff0c;又分为冒泡排序和快速排序 4&#xff0c;归并…

【linux】服务器安装及卸载pycharm社区版教程

【linux】服务器安装及卸载pycharm社区版教程 【创作不易&#xff0c;求点赞关注收藏】 文章目录 【linux】服务器安装及卸载pycharm社区版教程1、到官网下载安装包2、通过终端wget下载安装包3、解压4、安装5、设置环境变量6、运行pycharm7、删除pycharm安装包、卸载pycharm …

从“卷模型”到“卷应用”:AI时代的价值重塑与个性化智能探索

&#x1f308;所属专栏&#xff1a;【其它】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…

使用独享代理IP安全性高不高?怎么辨别独享IP和共享IP?

在网络安全的多种工具和技术中&#xff0c;代理IP是常用的一种手段&#xff0c;尤其是在处理需要隐私保护和安全性的网络请求时。独享代理IP&#xff08;专用代理&#xff09;和共享代理IP是两种主要的代理类型&#xff0c;它们在安全性、性能和成本方面有着本质的区别。本文将…

【漏洞复现】华测监测预警系统2.2 UserEdit.aspx SQL注入

声明&#xff1a;本文档或演示材料仅用于教育和教学目的。如果任何个人或组织利用本文档中的信息进行非法活动&#xff0c;将与本文档的作者或发布者无关。 一、漏洞描述 华测监测预警系统2.2&#xff08;HuaCe Monitoring and Early Warning System 2.2&#xff09;是一款由华…

人工智能算法工程师(中级)课程9-PyTorch神经网络之全连接神经网络实战与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(中级)课程9-PyTorch神经网络之全连接神经网络实战与代码详解。本文将给大家展示全连接神经网络与代码详解&#xff0c;包括全连接模型的设计、数学原理介绍&#xff0c;并从手写数字识别到猫狗识…

【第32章】MyBatis-Plus之代码生成器配置

文章目录 前言一、概述1.特点说明2.示例配置3. 数据库配置 (DataSourceConfig) 二、全局配置 (GlobalConfig)1.方法说明2.示例配置 三、包配置 (PackageConfig)1. 方法说明2. 示例配置 四、模板配置 (TemplateConfig)1. 方法说明2. 示例配置 五、注入配置 (InjectionConfig)1. …

使用 exe4j 转换 Java jar 程序为 Windows 平台可执行文件 (.exe)

使用 exe4j 转换 Java jar 程序为 Windows 平台可执行文件 &#xff08;.exe&#xff09; 介绍exe4j 特点&#xff1a;转换全过程&#xff08;软件操作&#xff09;1、注册2、选择模式3、配置应用4、选择执行的方式&#xff08;我这里管这个叫呈现方式&#xff09;5、选择 JAR …

Mybatis 学习之 数字字符串判断“失效”问题

目录 1. 现象2. 原因3. 解决4. 特别注意 1. 现象 <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper…

Java 中的正则表达式

转义字符由反斜杠\x组成&#xff0c;用于实现特殊功能当想取消这些特殊功能时可能在前面加上反斜杠\ 例如在Java中\也具有特殊意义&#xff0c;前面加一个反斜杠表示取消特殊意义&#xff0c;表示1个普通的反斜杠\&#xff0c;\\\\表示2个普通的反斜杠\\。其实就是要求Java中的…

Python那些优质可视化工具!

作者&#xff1a;Lty美丽人生 https://blog.csdn.net/weixin_44208569 本次分享10个适用于多个学科的Python数据可视化库&#xff0c;其中有名气很大的也有鲜为人知的&#xff01; 1、matplotlib 两个直方图 matplotlib 是Python可视化程序库的泰斗。经过十几年它任然是Pytho…

【前端速通系列|第二篇】Vue3前置知识

文章目录 1.前言2.包管理工具npm2.1下载node.js2.2配置 npm 镜像源2.3 npm 常用命令 3.Vite构建工具4.Vue3组件化5.Vue3运行原理 1.前言 本系列文章旨在帮助大家快速上手前端开发。 2.包管理工具npm npm 是 node.js中进行 包管理 的工具. 类似于Java中的Maven。 2.1下载nod…

Autoware 定位之基于ARTag的landmark定位(六)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…

CSS相对定位和绝对定位的区别

CSS相对定位和绝对定位的区别 区别1&#xff1a;相对的对象不同 相对定位是相对于自己绝对定位是相对于离自己最近的有定位的祖先 区别2:是否会脱离文档流 相对定位不会脱离文档流&#xff0c;不会影响其他元素的位置绝对定位会脱离文档流&#xff0c;会影响其他元素的布局 代…

玩转springboot之SpringBoot打成jar包的结构

SpringBoot打成jar包的结构 springboot通常会打成jar包&#xff0c;然后使用java -jar来进行执行&#xff0c;那么这个jar包里的结构是什么样的呢 其中 BOOT-INF 中包含的classes是我们程序中所有的代码编译后的class文件&#xff0c;lib是程序所引用的外部依赖 META-INF 这个…

AM243-Timer

目录 简介初始化代码测试API补充 简介 定时中断。 初始化 开启定时器&#xff0c;最多支持8个硬件定时器 定时周期1ms 增加一个GPIO输出口PRG0_PRU1_GPO15/M4 &#xff0c;我们会在定时中断中每隔1ms翻转该引脚&#xff0c;理想情况下应该在该引脚上测得2ms周期500Hz的矩形…

手把手教你打数学建模国赛!!!第一天软件准备篇

第一天软件准备 MATLAB MATLAB&#xff08;Matrix Laboratory&#xff09;是一种强大的数值计算和科学编程软件。它提供了丰富的数学函数和工具&#xff0c;用于数据分析、算法开发、信号处理、图像处理、控制系统设计、仿真等应用领域。 MATLAB具有直观的语法&#xff0c;使…

Postman接口模拟请求工具使用技巧

Postman是一款非常强大的接口模拟请求工具&#xff0c;可以帮助开发者快速测试、调试API接口。下面集合实际使用过程中的经验&#xff0c;分享大家一些基础使用技巧&#xff1a; 1. 安装与启动&#xff1a;首先在官网&#xff08;Download Postman | Get Started for Free&…

【Linux信号】阻塞信号、信号在内核中的表示、信号集操作函数、sigprocmask、sigpending

我们先来了解一下关于信号的一些常见概念&#xff1a; 实际执行 信号的处理动作 称为信号递达。 信号从产生到递达的之间的状态称为信号未决。 进程可以选择阻塞(Block)某个信号。 被阻塞的信号产生时是处于未决状态的&#xff0c;知道进程解除对该信号的阻塞&#xff0c;该…

零信任作为解决方案,Hvv还能打进去么?

零信任平台由“中心组件服务”三大部分构成&#xff0c;以平台形式充分融合软件定义边界&#xff08;SDP&#xff09;、身份与访问管理&#xff08;IAM&#xff09;、微隔离 &#xff08;MSG&#xff09;的技术方案优势&#xff0c;通过关键技术的创新&#xff0c;实现最佳可信…