C++的泛型编程

目录

1、模板

1.1、函数模板

1.2、类模板

1.3、模板类型形参

1.4、非模板类型参数

1.5、默认模板类型参数

1.6、友元模板函数

2、转换函数

转换函数的用途

示例

使用转换函数

注意事项

 转换函数的优点和缺点

结论

3、智能指针

4、STL

数据结构

4.1、序列容器 (Sequence Containers): 元素按照顺序存储,可以通过索引访问。

4.2、关联容器(Associative Containers): 元素按照键值对存储,可以通过键快速查找元素。

4.3、配器  (Adapters): 容器适配器是对现有容器的包装,提供了不同的接口。

算法

迭代器 

函数对象


C++ 的泛型编程主要通过模板(template)实现。模板允许编写能够处理多种数据类型的代码,而无需为每种数据类型编写单独的函数或类。 这通过参数化类型来实现,编译器会在编译时根据实际使用的类型生成具体的代码。

1、模板

1.1、函数模板

函数模板是 C++ 中的一种泛型编程机制,允许编写可以处理不同数据类型的函数。函数模板使用 template <typename T> (或 template <class T>) 声明类型参数 T,然后在函数体中使用 T 就像使用普通类型一样。

例如:

template <typename T>
T max(T a, T b) {return (a > b) ? a : b;
}

这个函数模板可以用来计算两个整数、浮点数或字符串的最大值。 

1.2、类模板

类模板是 C++ 中的一种泛型编程机制,允许编写可以处理不同数据类型的类。类模板使用 template <typename T> (或 template <class T>) 声明类型参数 T,然后在类成员函数和成员变量中使用 T。

例如:

template <typename T>
class Container {
public:Container() {}void push_back(T value) { data_.push_back(value); }
private:std::vector<T> data_;
};

这个类模板可以用来创建容器类,可以存储整数、浮点数、字符串等不同数据类型。 

1.3、模板类型形参

模板类型形参是 C++ 中的一种机制,允许将类型参数传递给模板函数或类。模板类型形参使用 typename 关键字声明。

例如:

template <typename T>
T foo(T value) {return value;
}

这个函数模板使用了模板类型形参 T,表示函数可以处理不同数据类型的值。 

1.4、非模板类型参数

非模板类型参数是 C++ 中的一种机制,允许将非类型参数传递给模板函数或类。非模板类型参数使用 const 关键字声明。

例如:

template <typename T>
void foo(T value, const int size) {// 使用 size 参数
}

这个函数模板使用了非模板类型参数 size,表示函数可以处理不同数据类型的值,并且有一个非类型参数 size。 

1.5、默认模板类型参数

默认模板类型参数是 C++ 中的一种机制,允许将默认值赋给模板类型形参。默认模板类型参数使用 = 关键字声明。 

例如:

template <typename T = int>
T foo(T value) {return value;
}

这个函数模板使用了默认模板类型参数 T = int,表示如果不指定类型参数 T,函数将使用整数类型。 

1.6、友元模板函数

友元模板函数是 C++ 中的一种机制,允许一个类访问另一个类的模板函数。友元模板函数使用 friend 关键字声明。

例如:

template <typename T>
class Container {
public:friend T foo(T value) {return value;}
};

这个类模板使用了友元模板函数 foo,表示容器类可以访问 foo 函数。

这些机制可以组合使用,以实现更加灵活和高效的泛型编程。

2、转换函数

转换函数是类的成员函数,用于将类对象转换为其他类型。转换函数没有返回类型,没有参数,并且不能声明为 constvolatile 或 static。转换函数的格式如下:

operator type();

其中,type 是目标类型。

转换函数的用途

转换函数的主要用途是实现类型转换,使得类对象可以在需要其他类型的地方使用。例如,可以将一个类对象转换为整数、浮点数或其他类对象。

示例

假设我们有一个表示距离的类 Distance,我们希望能够将 Distance 对象转换为整数(以厘米为单位)。我们可以定义一个转换函数:

class Distance {
private:int meters;int centimeters;public:Distance(int m, int cm) : meters(m), centimeters(cm) {}// 转换函数operator int() const {return meters * 100 + centimeters;}
};

在这个例子中,operator int() 是一个转换函数,它将 Distance 对象转换为整数类型。

使用转换函数

转换函数可以隐式调用。例如:

Distance d1(1, 50); // 1 米 50 厘米
int totalCm = d1; // 隐式调用转换函数,totalCm 的值为 150

也可以显式调用转换函数:

Distance d1(1, 50); // 1 米 50 厘米
int totalCm = d1.operator int(); // 显式调用转换函数,totalCm 的值为 150

注意事项

  1. 隐式转换:转换函数可以导致隐式类型转换,这可能会引起意外的行为。因此,在设计类时要谨慎使用转换函数。
  2. 显式转换:如果希望避免隐式转换,可以使用 explicit 关键字来声明转换函数。例如:
class Distance {
private:int meters;int centimeters;public:Distance(int m, int cm) : meters(m), centimeters(cm) {}// 显式转换函数explicit operator int() const {return meters * 100 + centimeters;}
};

 使用 explicit 关键字后,转换函数只能显式调用:

Distance d1(1, 50); // 1 米 50 厘米
int totalCm = static_cast<int>(d1); // 显式调用转换函数,totalCm 的值为 150

 转换函数的优点和缺点

优点

  • 提供了一种方便的方式来实现类型转换。
  • 可以使类对象在需要其他类型的地方使用。

缺点

  • 可能会引起意外的隐式类型转换,导致代码难以理解和调试。
  • 在某些情况下,可能会导致性能开销。

结论

转换函数是 C++ 中实现类型转换的强大工具,但需要谨慎使用。通过合理设计和使用 explicit 关键字,可以避免隐式转换带来的问题,提高代码的可读性和可维护性。

3、智能指针

智能指针的概念

智能指针是 C++ 中的一种特殊类型的指针,它可以自动地管理内存的分配和释放。智能指针可以帮助开发者避免内存泄漏和野指针的问题。

智能指针的实现

智能指针通常是通过使用模板来实现的。智能指针的实现通常包括以下几个部分:

  1. 引用计数器:智能指针使用引用计数器来跟踪指针指向的对象的引用次数。如果对象的引用次数为 0,智能指针将自动释放对象的内存。
  2. 指针:智能指针包含一个指针,指向对象的内存地址。
  3. 管理函数:智能指针提供了一些管理函数,例如 reset()get()operator->() 等,可以用来管理指针和对象。

智能指针的分类

智能指针可以分为以下几种:

  1. unique_ptr:unique_ptr 是一种独占的智能指针,它只能被赋值一次。unique_ptr 使用引用计数器来管理对象的引用次数。
  2. shared_ptr:shared_ptr 是一种共享的智能指针,它可以被赋值多次。shared_ptr 使用引用计数器来管理对象的引用次数。
  3. weak_ptr:weak_ptr 是一种弱引用智能指针,它不持有对象的所有权。但是,它可以访问对象的内存。

智能指针的使用

智能指针可以在很多场景下使用,例如:

  1. 内存管理:智能指针可以用来管理内存的分配和释放,避免内存泄漏和野指针的问题。
  2. 对象管理:智能指针可以用来管理对象的生命周期,避免对象的内存泄漏和野指针的问题。
  3. 资源管理:智能指针可以用来管理资源的释放,例如文件、网络连接等。

智能指针的优点和缺点

优点

  1. 自动内存管理:智能指针可以自动地管理内存的分配和释放,避免内存泄漏和野指针的问题。
  2. 简化代码:智能指针可以简化代码,避免使用原始指针和手动内存管理。
  3. 提高安全性:智能指针可以提高代码的安全性,避免内存泄漏和野指针的问题。

缺点

  1. 性能开销:智能指针可能会带来性能开销,例如引用计数器的计算和对象的复制。
  2. 复杂性:智能指针可能会增加代码的复杂性,需要了解智能指针的实现机制和使用方法。
  3. 限制:智能指针可能会限制开发者的自由度,例如不能使用原始指针和手动内存管理。

结论

智能指针是 C++ 中的一种特殊类型的指针,它可以自动地管理内存的分配和释放。智能指针可以提高代码的安全性和简化代码,但是也可能会带来性能开销和复杂性。开发者需要根据具体情况选择合适的智能指针类型和使用方法。

4、STL

C++ 的 STL (Standard Template Library,标准模板库) 是一个强大的工具集,提供了许多常用的数据结构和算法,极大地提高了 C++ 程序的开发效率。它包含以下几个主要组件:

数据结构

4.1、序列容器 (Sequence Containers): 元素按照顺序存储,可以通过索引访问。

  • vector: 动态数组,支持快速随机访问,插入和删除元素在尾部效率高,在中间效率低。
  • deque: 双端队列,支持快速在头部和尾部插入和删除元素。
  • list: 双向链表,支持快速在任意位置插入和删除元素,但随机访问效率低。
  • forward_list: 单向链表,只支持单向遍历,比 list 更节省空间。
  • array: 固定大小的数组,在编译时确定大小。

4.2、关联容器(Associative Containers): 元素按照键值对存储,可以通过键快速查找元素。

  • set: 存储唯一元素的集合,元素按顺序排列。
  • multiset: 存储元素的集合,允许重复元素,元素按顺序排列。
  • map: 键值对映射,键唯一,按键排序。
  • multimap: 键值对映射,键可以重复,按键排序。
  • unordered_set: 存储唯一元素的集合,元素无序,查找效率高。
  • unordered_multiset: 存储元素的集合,允许重复元素,元素无序,查找效率高。
  • unordered_map: 键值对映射,键唯一,无序,查找效率高。
  • unordered_multimap: 键值对映射,键可以重复,无序,查找效率高。

4.3、配器  (Adapters): 容器适配器是对现有容器的包装,提供了不同的接口。

  • stack: 栈,后进先出 (LIFO)。
  • queue: 队列,先进先出 (FIFO)。
  • priority_queue: 优先级队列,元素按优先级排序。

算法

算法 (Algorithms): STL 提供了大量的算法,用于对容器中的数据进行操作,例如排序、查找、复制、删除等。这些算法都是泛型的,可以应用于各种容器。 常见的算法包括:

  • sort(): 排序
  • find(): 查找
  • copy(): 复制
  • remove(): 删除
  • transform(): 变换
  • accumulate(): 求和
  • min_element()max_element(): 查找最小/最大元素

迭代器 

迭代器 (Iterators): 迭代器是访问容器元素的一种方式,它提供了一种统一的接口来访问不同容器中的元素。迭代器类似于指针,但比指针更安全,更灵活。 迭代器类型包括:

  • 输入迭代器 (Input Iterator)
  • 输出迭代器 (Output Iterator)
  • 前向迭代器 (Forward Iterator)
  • 双向迭代器 (Bidirectional Iterator)
  • 随机访问迭代器 (Random Access Iterator)

函数对象

 函数对象 (Functors): 函数对象是重载了 operator() 的类对象,可以像函数一样使用。函数对象可以用来定制算法的行为。

STL 的优势:

  • 代码重用性: STL 提供了大量的预定义组件,可以减少代码编写量,提高代码重用性。
  • 效率: STL 的组件都是经过高度优化的,效率很高。
  • 可扩展性: STL 的组件都是基于模板的,可以很容易地扩展到新的数据类型。
  • 标准化: STL 是 C++ 标准的一部分,所有符合标准的编译器都支持 STL。

使用 STL 的建议:

  • 选择合适的容器:根据实际需求选择合适的容器类型,例如,如果需要频繁插入和删除元素,则可以选择 list 或 deque;如果需要快速随机访问元素,则可以选择 vector
  • 理解迭代器:熟练掌握迭代器是使用 STL 的关键。
  • 使用算法:STL 提供了大量的算法,可以简化代码,提高效率。
  • 注意效率:虽然 STL 组件效率很高,但在某些情况下,仍然需要注意效率问题,例如,避免不必要的复制操作。

总而言之,C++ STL 是一个功能强大的工具集,熟练掌握 STL 可以大大提高 C++ 程序的开发效率和代码质量。 学习 STL 需要理解其核心组件之间的关系和使用方法,以及各种容器和算法的特性和适用场景。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【操作系统不挂科】<信号量(9)>选择题(带答案与解析)

前言 大家好吖&#xff0c;欢迎来到 YY 滴操作系统不挂科 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 本博客主要内容&#xff0c;收纳了一部门基本的操作系统题目&#xff0c;供yy应对期中考试复习。大家可以参考 本章为选择题题库&#xff0c;试卷…

服务器数据恢复—raid5阵列故障导致上层系统分区无法识别的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌DL380服务器&#xff0c;服务器中三块SAS硬盘组建了一组raid5阵列。服务器安装Windows Server操作系统&#xff0c;划分了3个分区&#xff0c;D分区存放数据库&#xff0c;E分区存放数据库备份。 服务器故障&#xff1a; RAID5阵列中有一…

【ARM】MDK在debug模式下的Registers窗口包含哪些内容

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决客户对于Debug模式下&#xff0c;对于Registers窗口包含的内容了解。 2、 问题场景 Registers窗口是在进入到debug模式下后&#xff0c;就会出现一个窗口。窗口中包含了很多寄存器信息。但是对于具体内容不了解…

【后端】版本控制

版本控制 1. 什么是版本控制&#xff1f; 版本控制&#xff08;Revision control&#xff09;是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史&#xff0c;方便查看更改历史记录&#xff0c;备份以便恢复以前的版本的软件工程技术。简单来说就是用于管理…

高项 - 项目进度管理

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 博文更新参考时间点&#xff1a;2024-12 高项 - 章节与知识点汇总&#xff1a;点击跳转 文章目录 高项 - 项目进度管理进度管理ITO规划监控 管理基础项目进度计划的定义和总要求管理新实践用户故事&#xff08;补…

【数据结构】【线性表】【练习】反转链表

申明 该题源自力扣题库19&#xff0c;文章内容&#xff08;代码&#xff0c;图表等&#xff09;均原创&#xff0c;侵删&#xff01; 题目 给你单链表的头指针head以及两个整数left和right&#xff0c;其中left<right&#xff0c;请你反转从位置left到right的链表节点&…

鸿蒙原生应用开发元服务 元服务是什么?和App的关系?(保姆级步骤)

元服务是什么&#xff1f;和App的关系&#xff1f; 元服务是是一种HarmonyOS轻量应用形态&#xff0c;用户无需安装即可使用&#xff0c;具备随处可及、服务直达、自由流转的特征。 元服务是可以独立部署和运行的程序实体&#xff0c;独立于应用&#xff0c;不依赖应用可独立…

Redis中的String数据类型及相关命令

[经典面试题] redis虽然是单线程模型&#xff0c;为什么效率还这么高&#xff1f;速度这么快呢&#xff1f; 原因&#xff1a;1、redis主要访问内存&#xff0c;数据库则是主要访问硬盘。 2、redis的核心功能&#xff0c;比数据库的核心功能更简单。数据库对于数据的CRUD&…

远程管理不再难!树莓派5安装Raspberry Pi OS并实现使用VNC异地连接

前言&#xff1a;大家好&#xff01;今天我要教你们如何在树莓派5上安装Raspberry Pi OS&#xff0c;并配置SSH和VNC权限。通过这些步骤&#xff0c;你将能够在Windows电脑上使用VNC Viewer&#xff0c;结合Cpolar内网穿透工具&#xff0c;实现长期的公网远程访问管理本地树莓派…

本地部署 Chat Nio

本地部署 Chat Nio 0. 引言1. 本地部署2. 访问 Chat Nio3. 渠道设置4. 聊天 0. 引言 Chat Nio 的功能&#xff1a; &#x1f916;️ 丰富模型支持: 多模型服务商支持 (OpenAI / Anthropic / Gemini / Midjourney 等十余种格式兼容 & 私有化 LLM 支持)&#x1f92f; 美观 …

C# OpenCV 通过高度图去筛选轮廓

//输入图像 threshCropMap.ImWrite("D:\\test\\threshCropMap_BeforeFilterByBlob.bmp"); //设定我们要筛选的高度 var ResultHeight 60; //创建对应高度的图像&#xff0c;由于是高度信息图&#xff0c;所有要使用32位来存放数据 Mat mat new Mat(filter.Rows, fi…

23.UE5删除存档

2-25 删除存档制作_哔哩哔哩_bilibili 按照自己的风格制作删除按钮 这样该行的存档就被从存档列表中删除了&#xff0c;并且实际存档&#xff08;我的存档蓝图&#xff09;中也被删除了 但是存在一个问题&#xff0c;如果存档数据中存在索引为: 0 1 2 3的存档&#xff0c;当索…

【graphics】图形绘制 C++

众所周知&#xff0c;周知所众&#xff0c;图形绘制对于竞赛学僧毫无用处&#xff0c;所以这个文章&#xff0c;专门对相关人员教学&#xff08;成长中的码农、高中僧、大学僧&#xff09;。 他人经验教学参考https://blog.csdn.net/qq_46107892/article/details/133386358?o…

kafka基础

文章目录 一、Kafka入门1.1、JMS1.2、生产者-消费者模式1.3、ZooKeeper 二、kafka基础架构2.1、producer2.2、kafka cluster2.2.1、broker2.2.2、Controller2.2.3、Topic2.2.4、Partition2.2.5、Replication2.2.6、Leader & Follower 2.3、consumer 一、Kafka入门 Kafka是一…

PMP–一、二、三模、冲刺–分类--5.范围管理--技巧--需求跟踪矩阵

文章目录 技巧一模反例不选“需求跟踪矩阵”4.整合管理86、 [单选] 项目经理加入一个项目&#xff0c;但项目经理在该项目所涉及的行业经验有限&#xff0c;在该项目的整个生命周期中&#xff0c;项目经理精心记录每个差距、问题和不一致性。但是&#xff0c;无论项目经理如何记…

掌握Golang中的数据竞争检测:runtime/race包全面教程

掌握Golang中的数据竞争检测&#xff1a;runtime/race包全面教程 引言数据竞争问题概述数据竞争的定义数据竞争对程序的影响常见数据竞争场景 Golang runtime/race包概述runtime/race包简介启用数据竞争检测使用 go run使用 go build使用 go test 基本用法与示例单元测试中的使…

ThreadLocal父子线程、线程池数据传递解决

多线程并发数据访问&#xff0c;确保数据安全至关重要&#xff0c;常用保证数据安全的方法有对代码synchronized锁、Lock锁&#xff0c;以及基于CAS的原子类&#xff0c;这些都是通过数据共享保障数据安全的&#xff0c;今天聊一聊另一种方案ThreadLocal线程副本&#xff0c;实…

Docker 从入门到精通全攻略

一、Docker 初印象 Docker 诞生于 2013 年&#xff0c;由 dotCloud 公司发起&#xff0c;最初是一个公司内部项目。其诞生背景源于程序员们苦于应用部署环境的复杂性&#xff0c;开发、测试、部署过程中各种库的依赖纷繁复杂&#xff0c;版本差异以及测试环境与部署环境不一致等…

WordPress设置自动更新CSS版本号

WordPress 通常会在引用 CSS 文件时添加版本号参数&#xff08;?verx.x.x&#xff09;。如果版本号未更新&#xff0c;浏览器可能继续加载旧的文件。 解决方法&#xff1a;确保你在 functions.php 文件中正确加载了 CSS 文件&#xff0c;并动态更新版本号。例如在functions.p…

达梦 DG

监视器 switchover 关于达梦DG switchover的细节&#xff0c;以下是一些关键步骤和注意事项&#xff1a; • 切换前检查确认&#xff1a; • 确认数据库版本和DG架构&#xff0c;包括IP信息及切换角色前后的情况。 • 检查DG切换方式&#xff0c;是switch over还是fail ove…