C++【模板初阶】

news2024/9/30 19:26:50

✨个人主页: Yohifo
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源

  • No one saves us but ourselves, no one can and no one may. We ourselves must walk the path.

    • 除了我们自己,没有人能拯救我们,没有人可以,也没有人可以。我们自己必须走这条路。

    配图


文章目录

  • 📘前言
  • 📘正文
    • 📖范型编程
    • 📖函数模板
      • 🖋️使用方法
      • 🖋️实现原理
        • 💡隐式实例化
        • 💡显式实例化
      • 🖋️匹配规则
      • 🖋️注意事项
    • 📖类模板
      • 🖋️使用方法
      • 🖋️注意事项
  • 📘总结


📘前言

早在北宋年间,中国的毕昇就已经发明了泥活字,标志着四大发明之一的活字印刷术正式诞生,从此文化传播取得了革命性突破,各种文学作品得以走进千家万户。倘若这项技术还没有被发明,那么恐怕我们现在的书本都还得靠逐字手抄传播,效率是非常低的

我们的程序也是如此,很多需要频繁使用的函数每次都得手动写,这可难不倒程序员,于是在上世纪80年代末,范型编程思想正式诞生,它就像是印刷文字的模具,将程序主体刻在其中,需要使用时让编译器根据参数类型生成即可,这就是我们今天的主角模板

活字印刷术


📘正文

模板的产生源自于范型编程的思想,简单来说,就是将算法抽象化编写

📖范型编程

那么什么才是一个抽象化的算法呢?

比如我们常用的两数相加函数,按照以前的写法,处理整型数据时,编写整型的方法;处理浮点型时,又得编写一个浮点型的加法,好在C++支持函数重载,使得我们可以存在同名函数,假若是C语言实现时,我们甚至要写两个不同名的相加函数

//处理整型的加法函数
int Add(const int& a, const int& b)
{
	return a + b;
}

//处理浮点型的加法函数
double Add(const double& a, const double& b)
{
	return a + b;
}

两数相加,直接返回两数之和就行了,我们实现方法时,没必要关注具体数据类型

将具体问题抽象化,直接假设数据类型为 T,利用模板实现如下:

//利用模板实现函数
template <class T>	//模板关键字
T Add(const T& a, const T& b)
{
	return a + b;
}

此时我们只编写了一个加法函数模板,而所有类型的参数都可以调用加法函数
示例
具体问题抽象化就是范型编程的核心思想


📖函数模板

首先来看模板在函数实现上的运用

注意:

  • 模板关键字为 template
  • 形式为 template <class T> 或者 template <typename T>
  • 其中的T是模板中的参数名,我们可以自定义
  • 模板中可以存在多个参数,通过 , 号分隔

🖋️使用方法

模板函数即在函数实现之前,写好模板,再根据模板中定义的变量名实现函数

//实现所有类型数组的打印
//这种模板写法也是没有问题的
template <typename Type>
void CoutArray(const Type& arr)
{
	//范围 for ,C++11 中的语法糖
	for (auto e : arr)
	{
		cout << e << " ";
	}

	cout << endl;
}

演示
我们还可以实现多参数模板

//多参数模板
//这里实现的是val2强制类型转换为val1,并取得和
template <class T1, class T2>
T1 getTrunVal(const T1& val1, const T2& val2)
{
	const T1 tmp = (const T1)val2;
	return val1 + tmp;
}

示例

总之,在函数模板的存在下,我们不再需要再编写不同类型参数的相似函数了

🖋️实现原理

这个模板看着挺厉害,那么它的实现原理是什么呢?

其实很简单,只需要两样东西:编译器函数重载

当我们编写好函数模板后,编译器会记住这个模板的内容,当我们使用模板时,编译器又会根据参数类型,创建相应的、具体的函数供参数使用,而这就是函数重载的道理

形象化理解:

  • 假设我们的整个程序就是一个大城市
  • 在这个城市中,我们就是造物主编译器则是负责协助我们处理事情的
  • 假设在某一天,参数A提出它需要一栋房子(方法)造物主很不屑的给造好了房子
  • 一天后,参数B也说它也需要一栋房子(方法)造物主很快就满足了它的需求
  • 之后的每一天中,都会有参数说自己需要房子(方法),于是造物主坐不住了,他觉得这些参数很麻烦,明明大家都是同一个需求,还得自己不断重复实现
  • 于是他想了一个办法:将建造房子的图纸(模板)交给编译器编译器是完全服从于造物主的,造物主说:“小编啊,以后再有人找我建房子(方法),你就按照这个图纸(模板)去建造,建好后将房子所有者变成它就行了”,这样一来,造物主的工作量就减小了很多,重复相似的工作直接提供蓝图(模板),然后让编译器根据参数类型落实即可
  • 于是,函数模板就这样诞生了

建造房子
可以看出,不断建房子这件麻烦事仍然存在,毕竟不可能让所有参数都入住一栋房子,函数模板 的本质就是将实现不同参数的相似方法这件事交给编译器去完成,我们只需要提供蓝图(模板)即可

比如文章开头中的 Add 函数,我们提供了模板,当实际调用函数时,编译器会自动识别参数类型,然后生成对应的函数,供参数调用,也就是说,编译器根据不同参数,老老实实生成了 intdoublechar 三个版本的 Add 函数,如果有需要,它还能继续生成

实际参数调用时,调用的是模板生成的对应函数,而非模板本身!

编译器在识别参数类型生成函数时,有两种途径:

  1. 自动识别 (隐式)
  2. 我们手动指定(显式)

💡隐式实例化

隐式实例化就是编译器自动识别参数后生成函数的过程

隐式实例化很方便,但可能存在问题

//Add 模板
template <class T>
T Add(const T& a, const T& b)
{
	return a + b;
}

int main()
{
	Add(2, 1.5);	//此时编译失败!
	return 0;
}

失败
原因:

  • 此时我们的模板是单参数模板
  • 因为是编译器隐式实例化,当编译器识别到 2 时,将生成 int 型方法
  • 此时 Add 函数内的两个形参类型都为 int,实际函数名修饰为 _3Addii
  • 而我们的参数2为 double ,是一个浮点型数据,实际函数调用时,找的是这个函数_3Addid
  • 此时出现明显的链接错误,编译器索性直接在编译前就已经报错阻拦

解决方法:

  • 将参数2强制类型转换为 int,或者将参数1强制类型转换为 double 都能解决问题
  • 多参数模板也能解决问题,此时如果识别到两个不同的参数,编译器就会根据实际情况生成函数
  • 还有一种解决方法就是显式实例化

转换
注意:

  • 强制类型转换后生成临时变量进行传参
  • 临时变量具有常性,所以Add函数中的引用形参需要被 const 修饰
  • 或者不用引用,这样也不需要 const ,但是此时效率会变低

💡显式实例化

显式实例化就是给编译器打招呼,让它在建房子时按照我们的意愿来

Add<int> (2, 3.14);	//此时编译器会调用 _3Addii 函数,至于传参时的类型转换,由编译器完成
Add<char> (2, 5);	//调用 _3Addcc 函数

这种行为是完全合法的,< > 符号也正式和我们见面了,在后面的 STL 学习中,< > 会经常使用到,比如生成一个类型为 int 的顺序表,直接 vector<int>,生成 char 类型的顺序表 vector<char>,一键生成,非常方便,当然还有很多容器都会用到显式实例化

🖋️匹配规则

具体函数调用时,隐式生成的模板函数并不会最先被调用

假设我们已经在程序中写好了参数需要的函数,而同时模板也能生成参数需要的函数,此时编译,编译器会先寻找是否存在目标函数,如果有,编译器便不再根据函数模板生成函数,避免造成代码冗余

我们可以通过调试来观察到这一现象

规则

🖋️注意事项

注意:

  • 函数调用时,并非直接调用函数模板,而是调用编译器根据参数类型模板生成的函数
  • 使用模板是在麻烦编译器帮我们办事,实际事也是办成功的
  • 隐式实例化后的函数已存在时,不会去生成模板函数,而是直接使用已存在的函数
  • 显式实例化后,编译器则会优先选择显式生成的普通函数
  • 隐式生成的模板函数不存在类型隐式类型转换显式后生成的是普通函数,可以隐式类型转换

模板中的参数类型不能为 strcut

template<struct T>	//这种定义是非法的

C++库中存在一个 swap 函数,它能实现所有数据类型的交换,其实它就是通过函数模板实现的
swap


📖类模板

模板除了可以用在函数上面外,还可以用在上,此时称为 类模板

STL 库中的容器,都是 类模板 的形式,我们使用时,需要什么类型的 ,直接显式实例化为对应 模板类 即可

//简单演示下 STL 中的容器,这些都是类模板的实际运用
vector<int> v1;	//实例化为整型顺序表类
list<double> l1;	//实例化为浮点型链表类

🖋️使用方法

类模板函数模板有所不同,类模板只能显式实例化

//简单写一个栈模板
template<class T>
class Stack
{
public:
	//构造函数
	Stack(int capacity = 4);

	//析构函数
	~Stack();

	//……

private:
	T* _pData;
	int _top;
	int _capacity;
};

//注意类模板中方法的实现方式!
//定义构造函数
template<class T>
Stack<T>::Stack(int capacity)
{
	_pData = new T[capacity];	//内存管理,一次申请4块空间
	_capacity = capacity;
	_top = 0;
}

//定义析构函数
template<class T>
Stack<T>::~Stack()
{
	delete[] _pData;	//注意:匹配使用
	_capacity = _top = 0;
}

//……

这就算 STL 库中 stack 的简陋版本,还有很多方法没实现,但大体逻辑都是如此

栈

🖋️注意事项

类模板使用时需要注意一些问题:

  • 模板类中的函数在定义时,如果没有在类域中,就需要通过 类模板+ 类域访问 的方式定义
  • 类模板 不支持声明与定义分开在两个文件中实现,因为会出现链接错误

📘总结

以上就是关于 C++ 模板初阶 的全部内容了,模板是一个很实用的工具,它可以提高我们的编码效率,省去很多不必要的麻烦,善用模板,快乐编程!

如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!

如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正


星辰大海

相关文章推荐

C/C++【内存管理】

===============

类和对象实操

类和对象实操之【日期类】

===============

类和对象系列

类和对象(下)

类和对象(中)

类和对象(上)

感谢支持

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

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

相关文章

FreeRTOS-Tickless低功耗模式 | FreeRTOS十四

目录 说明&#xff1a; 一、低功耗模式简介 1.1、STM32低功耗模式 二、Tickless模式 2.1、Tickless模式如何功耗 2.2、Tickless模式设计思想 2.3、为了降低功耗&#xff0c;又不影响系统运行&#xff0c;怎么能做到呢&#xff1f; 三、Tickless模式修改配置 3.1、配置…

如何提升 ETF 期权隐含波动率和希腊值的计算速度?

期权的隐含波动率可以反应市场对未来的预期&#xff0c;通常使用牛顿法和二分法来计算。这两种方法都需要频繁迭代&#xff0c;且迭代次数不能确定&#xff0c;核心代码无法向量化&#xff0c;因此只能通过循环来逼近求解。这就导致在期权相关计算中&#xff0c;隐含波动率往往…

PO模式在Selenium中简单实践

初识PO模式 PO&#xff08;PageObject&#xff09;是一种设计模式。简单来说就是把一些繁琐的定位方法、元素操作方式等封装到类中&#xff0c;通过类与类之间的调用完成特定操作。 PO被认为是自动化测试项目开发实践的最佳设计模式之一。 在学习PO模式前&#xff0c;可以先…

InstructGPT笔记

一、InstructGPT是在GPT3上微调&#xff0c;ChatGPT是在GPT3.5上微调 二、该论文展示了怎么样对语言模型和人类意图之间进行匹配&#xff0c;方法是在人类的反馈上进行微调。 **三、方法简介&#xff1a;**收集很多问题&#xff0c;使用标注工具将问题的答案写出来&#xff0…

大数据面试题flume篇

1.Flume 的Source&#xff0c;Sink&#xff0c;Channel 的作用&#xff1f;你们Source 是什么类型&#xff1f; 1. 作用 &#xff08;1&#xff09;Source组件是专门用来收集数据的&#xff0c;可以处理各种类型、各种格式的日志数据&#xff0c;包括 avro、thrift、exec、jm…

Nginx介绍及安装(windows版,Linux版)

目录 一、Nginx介绍 1、Nginx优势 2、Nginx作用 3、部署静态资源 4、代理 5、负载均衡 二、Nginx安装步骤&#xff08;windows版&#xff09; 三、Nginx安装步骤&#xff08;Linux版&#xff09; 1、官网下载安装包&#xff0c;下载完之后上传到Linux系统上 2、在Lin…

股票量化策略是如何被执行出来的?

在股票量化方面&#xff0c;很多投资者是不知道怎么样挖掘量化策略&#xff0c;便在量化交易接口方面会通过股票交易接口将数据慢慢挖掘出来&#xff0c;就简单的通过api接口调用数据方面&#xff0c;直接通过交易接口端输出交易持仓数据&#xff0c;并且通过交易系统对数据的筛…

什么是“镜像浏览”?文件夹加密后的镜像浏览有什么用?

电脑中的文件夹经常用来储存各种重要文件&#xff0c;加密保护成为很多人的选择&#xff0c;而夏冰加密软件拥有各种适用于不同场景的文件夹加密软件&#xff0c;备受用户喜爱。在我们打开加密文件夹之后&#xff0c;我们可以在加密控制面板中发现“镜像浏览”的按钮&#xff0…

Sharding-jdbc

一、概念理解垂直切分&#xff1a;包含垂直分库和垂直分表1.1、垂直分库 &#xff1a;专库专用&#xff08;按照业务类型对表分类&#xff09;1.2、垂直分表&#xff1a;基于数据表的列&#xff08;字段&#xff09;为依据切分的&#xff0c;是一种大表拆小表的模式。1.3、垂直…

【Python--torch(激活函数说明+代码讲解)】激活函数(sigmoid/softmax/ELU/ReLU/LeakyReLU/Tanh)

【Python–torch】激活函数(sigmoid/softmax/ELU/ReLU/LeakyReLU/Tanh) 文章目录【Python--torch】激活函数(sigmoid/softmax/ELU/ReLU/LeakyReLU/Tanh)1. 介绍2. 常用激活函数说明2.1 Sigmoid2.1.1 公式2.1.2 图像2.1.3 代码解读2.2 Softmax2.2.1 公式2.2.2 代码解读2.3 ELU2.…

荧光探针Pyrene-PEG2-Propargyl,芘甲酰胺-二聚乙二醇-丙炔

Pyrene-PEG2-Propargyl物理参数&#xff1a; CAS号&#xff1a;N/A | 英文名&#xff1a;Pyrene-PEG2-Propargyl |中文名&#xff1a;芘甲酰胺-二聚乙二醇-丙炔分子式&#xff1a;C24H21NO3分子量&#xff1a;371.44纯度标准&#xff1a;95%外形颜色&#xff1a;淡黄色或白色固…

shell学习4

目录 一、统计文本中的词频 二、压缩javascript 三、打印文件的或行中的第n个单词或列---awk 3.1 利用awk打印文件中每行中的第五个单词。 3.2 利用awk打印当前目录下的文件的权限和文件名 3.3 利用awk打印从M行到N行这个范围内的所有文本 3.4 利用awk 部分提取文件中的内…

opencv复习

文章目录图像衡量结果&#xff08;损失函数&#xff09;预测的好坏前向传播 反向传播图像 实质是矩阵 长 宽 像素通道&#xff08;0-255 0 黑 255 亮&#xff09; 假设这里做一个10分类 行向量✖列向量是一个数 分类 最后的结果是一个各个分类的概率值 这里的b是偏置项&…

学校节能降耗减排方案——能耗监管平台的建设及效果剖析

摘要&#xff1a;作为崭新的校园能耗管理手段&#xff0c;能耗监测平台以传统管理方式无法企及的优势有力地提升了高校能源管理工作的水平&#xff0e;从而受到了相关管理者的青睐。本文梳理总结了高校能耗监测平台的基本组成和优势特点&#xff0c;同时对能耗平台建设和使用中…

nginx设置重定向跳转后ip:[端口]/abc变成ip/abc而报错404

nginx设置重定向跳转后 ip:[端口]/abc 变成 ip/abc 而报错404nginx配置&#xff1a;server {listen 80;server_name _;client_max_body_size 300m;absolute_redirect off;location / {root html;index index.html index.htm;proxy_set_header X-Real-IP $remote_a…

【nodejs-04】黑马nodejs学习笔记04-MySQL简介及安装

文章目录1.数据库的基本概念1.1什么是数据库1.2 常见的数据库及分类1.3 传统型数据库的数据组织结构2.安装并配置MySQL2.1 了解需要安装哪些MySQL相关的软件2.2 MySQL 在 Mac 环境下的安装2.3 MySQL 在 Windows 环境下的安装1.数据库的基本概念 1.1什么是数据库 数据库&#x…

JavaWeb学习

文章目录Tomcat 详解1 Tomcat 安装2 默认端口号3 面试题4 编写与发布一个网站Http 详解1 http 请求2 http 响应3 面试题Tomcat 详解 1 Tomcat 安装 进入Tomcat官网下载压缩包&#xff1a;https://tomcat.apache.org/ 将压缩包解压即可直接使用 启动Tomcat:bin目录下startup.b…

【软件测试】如何在测试团队中工作游刃有余?你的测试技巧......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 在测试团队中&#…

基于数据库实现分布式锁

分布式锁概述 前言 我们的系统都是分布式部署的&#xff0c;日常开发中&#xff0c;秒杀下单、抢购商品等等业务场景&#xff0c;为了防⽌库存超卖&#xff0c;都需要用到分布式锁。 分布式锁其实就是&#xff0c;控制分布式系统不同进程共同访问共享资源的一种锁的实现。如…

xshell6运行报错:由于找不到mfc110u.dll、MSVCR110.dll无法继续执行代码

今天给大家分享一下我刚装完系统遇到得问题,由于新盟的罗建雨【胡巴】老师帮我给电脑加了固态,又重装了系统,因此电脑里面得所有软件需要重装,在我重装的过程中遇到了一个小问题给大家分享一下,如果大家以后遇到也方便解决。 问题: 安装Xshell时电脑系统报错:“由于找…