【C++】21年精通C++之泛型编程和模板初阶知识

news2024/10/6 12:28:32

❤️前言

        大家好!今天和大家一起学习关于C++泛型编程和模板初阶的相关知识。

正文

        我们之前已经学习了C++中非常重要的一个特性——函数重载,函数重载很好地提高了我们代码的可读性。但是对于适配多种参数的某种函数来说,我们如果使用函数重载就需要编写多个函数来完成不同的需要,这样的话不仅我们写代码会很累,而且写出的代码也会变得冗余。也就是说代码的复用性较差,而且有时难以维护。

        那么我们就想:是否能做到我们交给编译器一个模板,它在运行时给我们根据需求创造出具体的事物并很好地完成相应的任务呢?

        显然我们的前辈们早就想到了这一点,提前栽下了一颗树,我们只需要在其下乘凉即可,在C++中解决问题的方法就是——泛型编程

        泛型编程的含义是编写与类型无关的通用代码,它是代码复用的一种手段。模板是泛型编程的基础。其中,模板分为函数模板和类模板。

函数模板的概念与基本使用

        函数模板的概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

        知道了函数模板的概念,我们现在来看看函数模板的基本使用方式:

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表)
{...}

         其中,template是模板对应的关键字,typename是模板参数类型对应的关键字,只要我们在尖括号中写入了多个模板参数,我们就可以利用这些种类的模板参数对模板进行描述。具体的使用方式以交换函数Swap来展示:

// 交换任意的相同类型变量 a 、 b
template<typename T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}

        我们可以看到,T被我们用来当作一种类型来使用,如果我们进行函数调用和传参,那么这个类型就是固定的了,这时编译器就可以帮我们将这个模板转化成一个真实存在的函数,并且进行一系列的使用,这就是函数模板的基本使用方式了。

函数模板的实现原理

        根据我们上面对于函数模板的基本了解,我们大概可以得出如下的结论:函数模板是一个蓝图,它本身并不能完成函数的职能,但是它为编译器提供了模板,也就是起一个模具的作用。这种方式将我们本该做的很多重复的事情交给了编译器,减少了代码冗余,提高了写代码的效率。

         在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供 调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然 后产生一份专门处理double类型的代码,对于其他类型也是如此。

函数模型的实例化

        用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为隐式实例化显式实例化

隐式实例化:

        隐式实例化的意思是编译器根据实参推演模板参数的类型并生成实际函数。现在我们以上面的Swap函数来做例子详细介绍隐式实例化的使用方式:

// 在main函数中执行如下代码:
int main()
{
	int a = 0; int b = 1;
	int c = 0; double d = 1.0;
    // 正确的使用方式
	Swap(a, b);
    // 交换c、d的这条调用会失败并报错
	Swap(c, d);
	return 0;
}

        当我们像上面那样去写,我们会发现第二条代码出现了问题:

        也就是说,使用函数模板隐式实例化出的函数并不能进行对实参的隐式类型转换,不过这也很好理解,因为这里只有一个模板参数T,但是两个实参的类型并不相同,这时编译器也就无法判断它应该生成什么样的函数了。(编译器已经帮我们做了很多事了,所以我们在这里还是老老实实的按照规矩来写吧)

        要解决这个问题只有一个方式,就是手动在模板参数列表里加上一个参数,并对Swap函数进行改造:

// 将Swap函数进行改造
template<typename T1,typename T2>
void Swap(T1& t1, T2& t2)
{
	T1 tmp = t1;
	t1 = t2;
	t2 = tmp;
}

显式实例化:

        显式实例化是指在调用函数时在函数名后加上<>并在其中指定模板参数的实际类型。以Swap函数为例:

	int a = 0; int b = 1;
	Swap<int>(a, b);

模板参数的匹配原则

        我们可以对模板参数的匹配原则做一个小总结:

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。
  2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。当然,如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
  3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

类模板的定义

        类模板的基本定义方式:

template<class T1, class T2, ..., class Tn>
class 类模板名
{
     // 类内成员定义
}; 

        知道了基本使用方式之后,我们来编写一个顺序表的类模板:
 

// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{ 
public :
 // 构造函数
 Vector(size_t capacity = 10)
     : _pData(new T[capacity])
     , _size(0)
     , _capacity(capacity)
 {}
 
 // 使用析构函数演示:在类中声明,在类外定义。
 ~Vector();
 
 void PushBack(const T& data);
 void PopBack();
 // ...
 
 size_t Size() {return _size;}
 
 T& operator[](size_t pos)
 {
     assert(pos < _size);
     return _pData[pos];
 }
 
private:
 T* _pData;
 size_t _size;
 size_t _capacity;
};

// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{
     if(_pData)
     delete[] _pData;
     _size = _capacity = 0;
}

        定义类模板时需要注意的是,如果模板的成员在外定义时,应该要加上模板参数列表。而且当我们在外定义类成员时是需要在函数名前加上类名和作用域限定符的,这时对于类模板的区别就是要用显式实例化的形式才表示一个真的类名,例如上面Vector类的析构函数。

类模板的使用

        类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟 <>,然后将实例化的类型放在 <> 中即可,类模板的名字不是真正的类,而实例化的结果才是真正的类。

        具体使用方式如下:

// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

🍀结语

        谢谢大家的阅读,同时希望大家阅读了这篇文章之后能有所收获。祝看到这的大家能够天天开心!

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

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

相关文章

感知程序从ros切换到cyber_rt框架下,pcl相关问题

1.在ubuntu20.04下&#xff0c;原感知程序需要的是pcl1.8.1&#xff0c;车上其他程序使用的是pcl.1.10.0或者pcl1.10.0&#xff0c;在编译pcl1.10.0时会编译通不过&#xff0c;而pcl1.10.1可以顺利编译通过&#xff0c;安装pcl1.8.1时遇到的问题可能如下&#xff0c;及对应的修…

CTF必看~ PHP反序列化漏洞6:绝妙_wakeup绕过技巧

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

iptables防火墙2

iptables防火墙 一&#xff1a;SNAT原理与应用 SNAT 应用环境&#xff1a;局域网主机共享单个公网IP地址接入Internet&#xff08;私有不能早Internet中正常路由&#xff09;SNAT原理&#xff1a;修改数据包的源地址。 SNAT转换前提条件&#xff1a; 1.局域网各主机已正确设…

新星计划 Electron+vue2 桌面应用 2 搭建及运行

基础内容&#xff1a;新星计划 Electronvue2 桌面应用 1 基础_lsswear的博客-CSDN博客 根据使用过的经验和官网的描述&#xff0c;大概可以有四种方式&#xff1a; 自己创建项目&#xff08;仅使用npm&#xff09;用Electron脚手架HBuilder编译为web&#xff0c;再用Electron…

MSP432笔记4:时钟与滴答计时器

所用单片机型号&#xff1a;MSP432P401r 今日继续更新我的MSP432电赛速通笔记&#xff1a; 提示&#xff1a; 本节内容相当于讲述delay_ms&#xff08;&#xff09; 和delay_us&#xff08;&#xff09; 俩延时函数的由来&#xff0c; 所以不需要花费过多时间斟酌 MSP432单…

论文阅读_音频表示_wav2vec_2.0

论文信息 name_en: wav2vec 2.0: A Framework for Self-Supervised Learning of Speech Representations name_ch: wav2vec 2.0&#xff1a;语音表示自监督学习框架 paper_addr: http://arxiv.org/abs/2006.11477 date_read: 2023-04-27 date_publish: 2020-10-22 tags: [‘深…

C++深度解析:虚函数的使用与避免

C深度解析&#xff1a;虚函数的使用与避免 1. 虚函数的基本概念与原理 (Basic Concepts and Principles of Virtual Functions)1.1 虚函数的定义与作用 (Definition and Role of Virtual Functions)1.2 虚函数的底层实现 (Underlying Implementation of Virtual Functions)1.3 …

【CANN训练营0基础赢满分秘籍】进阶班 Atlas 200I DK 智能小车

1 智能小车三维结构设计 1.1 基本模块 坚固酷炫结构模块运动控制模块超声波传感器模块摄像头视觉模块其他传感器模块 1.2 结构设计基本原则 从零开始设计并搭建智能小车&#xff0c;在满足外观要求的基础上&#xff0c;要满足小车运转过程中的运动干涉率为O&#xff0c;并且…

【CANN训练营0基础赢满分秘籍】进阶班 应用开发深入讲解

1 AIPP AIPP (Artificial Intelligence Pre-Processing)人工智能预处理&#xff0c;在AI Corfe上完成数据预处理。 1.1 静态AIPP 构造AIPP配置文件*.cfg使能静态AIPP&#xff0c;将其配置参数保存在模型文件中。 atc --framework3--soc_versionS[soc_version) --model SHOM…

基于51单片机的电子琴Protues仿真设计

一、设计背景 基于51单片机的电子琴是一款由51单片机控制器、音频模块和硬件阵列组成的数字化乐器。它可以模拟各种乐器的音效&#xff0c;同时也具有许多常规电子琴所没有的高级功能。 首先&#xff0c;这种电子琴是以数字信号处理技术为基础的。通过软件编程&#xff0c;将…

【JUC】Java对象内存布局和对象头

【JUC】Java对象内存布局和对象头 文章目录 【JUC】Java对象内存布局和对象头1. 对象的内存布局1.1 对象头1.1.1 对象标记1.1.2 类元信息/类型指针 1.2 实例数据1.3 对齐填充 2. 测试 1. 对象的内存布局 在 HotSpot 虚拟机里&#xff0c;对象在堆内存中的存储布局可以划分为三…

MSP432学习笔记6:中断优先级管理

所用型号&#xff1a;MSP432P401R 今日继续我的MSP432电赛速通之路。 主要学习的是&#xff1a;中断优先级管理、软件挂起中断、屏蔽中断优先级 目录 MSP432具有8级可编程的中断优先级。 中断优先级管理库函数&#xff1a; 软件挂起中断&#xff1a; 屏蔽中断优先级&#…

微信小程序富文本插件mp-html

使用场景&#xff1a; 偏偏后端传过来的数据又要用到富文本标签&#xff0c;然后找了很多组件&#xff0c;要不就是下载量低&#xff0c;要不就是里面功能太少&#xff0c;只有这款mp-html组件深得我心&#xff0c;里面功能丰富&#xff0c;简单实用&#xff0c;真的绝绝子&…

DMA直接存储器存取

目录 存储器映像 寄存器 DMA框图 DMA基本结构 DMA请求映射 数据宽度与对齐 ​编辑 存储器到存储器 ​编辑 外设与存储器 来源b站江科大stm3入门教程 存储器映像 寄存器 DMA框图 AHB从设备&#xff08;DMA自身的寄存器&#xff09;连接在总线矩阵右侧的AHB总线上 所以DMA既…

LeetCode:509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

509. 斐波那契数 题目 斐波那契数 &#xff08;通常用 F(n) 表示&#xff09;形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始&#xff0c;后面的每一项数字都是前面两项数字的和。也就是&#xff1a; F(0) 0&#xff0c;F(1) 1 F(n) F(n - 1) F(n - 2)&#xff0c;…

无底线内卷?谈谈如何在职场中实现人生巅峰

在竞争激烈的职场上&#xff0c;各种职场难题时常出现&#xff0c;如何进行有效沟通、如何应对工作压力、如何提升职业能力等&#xff0c;这都是需要去克服的问题。 1. 尝试人际沟通A&#xff1a;TO 企业B&#xff1a;TO 员工 2. 适应工作压力A&#xff1a;原因B&#xff1a;TO…

ROS2 入门应用 创建启动文件(C++)

ROS2 入门应用 创建启动文件&#xff08;C&#xff09; 1. 创建功能包2. 添加依赖关系3. 添加编译信息4. 创建启动文件4.1. Python4.2. XML4.3. YAML 5. 编译和运行 1. 创建功能包 用Python、XML或YAML编写的启动文件可以启动和停止不同的节点&#xff0c;以及触发和处理各种事…

法规标准-GB/T 39323标准解读(2020版)

GB/T 39323是做什么的&#xff1f; GB/T 39323全称为乘用车车道保持辅助(LKA)系统性能要求及试验方法&#xff0c;其中主要描述了LKA系统的功能要求及测试要求 一般要求 1.系统应能在状态良好的车道边线环境下识别车辆与车道边线的相对位置&#xff0c;辅助驾驶员将车辆保持…

76.建立一个主体样式第二部分

上节课的时候我们完成的页面是这个样子&#xff01; ● 之后我们通过绝对定位来解决位置定位的问题 .header-container {width: 1200px;margin: 0 auto;position: absolute;left: 50%;top: 50%; }header {height: 100vh;background-color: orange;position: relative; }● 之…

通过Python的PyPDF2库提取pdf中的文字

文章目录 前言一、PyPDF2库是什么&#xff1f;二、安装PyPDF2库三、查看PyPDF2库版本四、使用方法1.引入库2.定义pdf路径3.打开PDF文件4.创建PDF阅读器对象5.获取PDF文件中的页数6.遍历每一页7.获取当前页内容8.提取当前页文本9.打印当前页文本10.效果 总结 前言 一、PyPDF2库…