【C++】——- 模板初阶介绍

news2024/12/29 23:55:13

前言:

  • 在之前的学习中,我们已经把 C++前期所需要用到的知识都给大家介绍了一遍。接下来,我们要学习的就是关于在C++ 中模板的基本知识,今天我带给大家的内容便是关于 模板初阶的介绍。


目录

(一) 泛型编程

(二)函数模板

1 、函数模板概念

2、函数模板格式

3 、函数模板的原理

4 、函数模板的实例化

①隐式实例化

②显式实例化

5、 模板参数的匹配原则

(三)类模板

 1 、类模板的定义格式

2 、类模板的实例化

(四)总结


(一) 泛型编程

首先,我通过交换两个函数的值的代码来大家初步认识!!!

首先,我先引出一个事情,在之前我们写交换两个数的函数时。随着给出的参数的不同的类型,我们写出的函数也不相同。具体如下:

  • 例如,🌜当我们交换的是两个 整形 的变量时,我们的参数的类型为 【int】;🌛
void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
  • 🌜当我们需要交换的参数为 字符 时,此时我们的参数类型则为【char】;🌛

void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}
  • 🌜当我们需要交换的参数为 浮点 时,此时我们的参数类型则为【double】;🌛
void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}

🔥注意事项:

使用函数重载虽然可以实现,但是有以下几个不好的地方:

  • 1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函 数
  • 2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

  • 如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件 (即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。

💨 因此基于上述这种情况,在C++中便引入了泛型编程的思想:

  • 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。
  • 模板是泛型编程的基础

💨 其中模板又可以分为以下两类:


(二)函数模板

1 、函数模板概念

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


2、函数模板格式

返回值类型 函数名(参数列表){}

template<typename T1, typename T2,......,typename Tn>
  • 因此,此时无论有所少种对象需要进行交换,我们只需要写一个模板即可
template<typename T>
void Swap( T& left, T& right)
{
 T temp = left;
 left = right;
 right = temp;
}

🔥注意

  • typename是用来定义模板参数关键字,也可以使用 【class】(切记:不能使用struct代替class)
  • 对比函数重载(同一作用域内函数名相同,参数列表不同的函数),函数模板只需要一个函数就实现了函数重载的部分功能(参数个数相同类型不同,函数重载需要定义多个同名参数列表不同的函数)

此时,问大家一个小问题

  •  大家可以看看调试代码:

小结:

  1. 通过以上调试,可能把对于好多说调用的不是一个的小伙伴都给“整不自信”了,之前认为是不一样的,现在一看调试,发现是一样的了。
  2. 真的是一样的吗?其实并不是一样的,我说过编译器有时也会欺骗你的眼睛,接下来我们去看看 底层的汇编结果是什么样的。

因此,此时我在问大家此处在调用的时候是调用的这个模板吗?

  • 我相信经过上述的演示,大家应该都知道了,我们调用的并不是这个模板,看到的只是用 “模具” 印刷出来的东西,

3 、函数模板的原理

那么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生 产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。因此有人给出了论调:懒人创造世界。

所以模板的原理就是:

  • 函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模 板就是将本来应该我们做的重复的事情交给了编译器 

🔥小结:

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

4 、函数模板的实例化

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

  • 模板参数实例化分为:隐式实例化和显式实例化

①隐式实例化

1. 隐式实例化:让编译器根据实参推演模板参数的实际类型

template<class T>
T Add(const T& left, const T& right)
{
 return left + right;
}
int main()
{
 int a1 = 10, a2 = 20;
 double d1 = 10.9, d2 = 20.1;
 Add(a1, a2);
 Add(d1, d2);
 return 0;
}

小结:

  1. 对于上述代码,我相信大家应该都知道是什么意思的哈!
  2. 那上述代码可以正常运行吗? 答案是可以的,这就是一个简单的实现加法的函数而已

此时问题来了,还是以上代码,大家看下面这段代码是否可以正常的运行呢?

 Add(a1,d1);

此时再去编译,就会报错:

🔥 解释说明:

  • 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
  • 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错

🔥注意:

  • 在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅

那么我们可以怎么解决这个问题呢?

此时有两种处理方式:

  • 1. 用户自己来强制转化

此时,我们可以把其中一个强转为和另外一个相同的类型就可以

Add(a1, (int)d1);
	
Add((double)a1, d1);
	

我们编译输出看结果:

②显式实例化

  •  2. 使用显式实例化

还有一种解决方法就是显示实例化,我们可以这样做:

int main(void)
{
 int a = 10;
 double b = 20.0;
 
 // 显式实例化
 Add<int>(a, b);
 return 0;
}
  • 如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

5、 模板参数的匹配原则

  • 1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{
 return left + right;
}

// 通用加法函数
template<class T>
T Add(T left, T right)
{
 return left + right;
}

void Test()
{
 Add(1, 2);      // 与非模板函数匹配,编译器不需要特化
}

此时,大家猜猜ADD会去调用哪个版本的加法函数呢?

我们从上述的调试可以发现,编译器最终去调用的是模板函数的方法。其实这很好理解,我举个例子:

  1. 假设有一天你爸妈都外出了中午不在家给你做饭,此时给你留了 100元当做中午的午餐费用,此时你是会 自己亲自动手去煮呢?还是直接点个外卖就完事了呢?反正对于我来说就是直接点个外卖。
  2. 在此也是同样的道理。

那假设此时你妈妈要求中午必须自己下厨煮来吃,不能点外卖,因为外卖不卫生,那么此时有什么方法呢?

  1. 此时我们就需要显示实例化操作
Add<int>(1, 2); 


(三)类模板

  • 类模板可以指定默认模板参数(函数模板不可以),跟函数参数的默认值一样,必须从右向左连续赋值默认类型;
  • 如果实例化对象时又传递了类型,默认类型会被覆盖掉,跟函数参数是一样的

 1 、类模板的定义格式

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

 此时,我们写了这样的一个栈


typedef double STDateType;
class stack
{
private:
	STDateType* _pData;
	size_t _size;
	size_t _capacity;

public:

};

int main()
{
	stack str1; //int
	stack str2; //double

	return 0;
}

🔥注意:

此时这个栈,能否做到一个存 int 类型的,一个存 double 类型的呢?

  1. 如果有这样的需要,那这段代码就不行了,此时我们就需要拷贝一份再去修改;
  2. 但是此时大家就会发现两份代码此时几乎是一致的;
  3. 因为为了避免造成这样的情况,我们让上述这种情况让编译器去做。

 此时,我们可以这样做:

template<class T>
class stack
{
private:
	STDateType* _pData;
	size_t _size;
	size_t _capacity;

public:
	stack(size_t capacity = 10)
		: _pData(new T[capacity])
		, _size(0)
		, _capacity(capacity)
	{}

	// 使用析构函数演示:在类中声明,在类外定义。
	~stack()
    {
      delete[] _pData;
     _size = _capacity = 0;
    }

};

int main()
{
	//必须显示实例化
	stack<int> str1; //int
	stack<double> str2; //double

	return 0;
}


2 、类模板的实例化

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

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

(四)总结

到此,关于模板的一些介绍我们就先讲到这里!在接下来我会详细的带领大家去学习这个知识!

最后,我们总结一下本文:

  1. 在本期,主要的目的就是带领大家认识关于C++中的模板的介绍;
  2. 首先带领大家的认识的就是关于泛型编程的基本思想。模板是泛型编程的重要思想,也是C++的精髓之一,C++的STL库完全通过模板实现;
  3. 紧接着分别简单的介绍了关于函数模板的基本知识。知道了函数模板的实例化和匹配规则等;
  4. 最后就是关于类模板的基本知识介绍。

以上便是全文的基本内容了!!感谢大家的观看!!!

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

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

相关文章

【Python_Opencv图像处理框架】图像形态学操作

写在前面 本篇文章是opencv学习的第三篇文章&#xff0c;主要讲解了图像的形态学有关操作&#xff0c;作为初学者&#xff0c;我尽己所能&#xff0c;但仍会存在疏漏的地方&#xff0c;希望各位看官不吝指正❤️ 写在中间 读完这篇文章后&#xff0c;相信您便能信手拈来下面图…

给照片换底色(python+opencv)

给照片换底色&#xff08;pythonopencv&#xff09; 本篇目录&#xff1a; &#x1f984; 一、分析照片基本信息 &#x1f984; 二、方法一&#xff08;遍历图像&#xff0c;将像素值点替换修改为指定颜色&#xff09; &#x1f984; 三、修改图片颜色方法二&#xff08;先转…

MySQL数据库索引

目录 0.知识回顾 1.数据库约束 一.索引 1.什么是索引 2.为什么要使用索引(作用) 3.索引的使用场景 4.如何使用索引 1.查看索引 2.创建索引 3.修改索引 4.删除索引 5.索引的分类 1.使用场景不同 2.按列区分 3.按数据组织方式 二.索引的数据结构 1.HASH 2.二叉搜…

如何设计自动化测试框架?阿里P7工程师耗时一个月总结而成

目录 一、什么是自动化测试框架 二、自动化测试框架的架构设计 三、自动化测试框架的最佳实践 四、自动化测试框架的组成部分 五、自动化测试框架的设计原则 六、如何选择自动化测试框架 七、自动化测试框架实例 八、结论 一、什么是自动化测试框架 自动化测试框架是一…

UE4/5多人游戏详解(八、游戏模式和游戏状态里的函数重写,插件内地图的地址做变量,做变量让按钮出现不同状态,插件内的所有代码)

目录 这里不写在插件里面&#xff0c;而是在游戏模式&#xff1a; 头文件&#xff1a; Cpp文件&#xff1a; 更改ini文件 进入地图设置模式&#xff1a; 写插件里面&#xff0c;做一个变量&#xff1a; 写变量 然后更改函数MenuSet&#xff1a; 在子系统中做变量&…

FPGA 20个例程篇:20.USB2.0/RS232/LAN控制并行DAC输出任意频率正弦波、梯形波、三角波、方波(四)

接着同样地我们也需要完成对千兆网口ETH模块和USB2.0模块的编写&#xff0c;实际上和UART串口模块的设计思想大同小异&#xff0c;也同样地需要完成两项关键功能即识别并解析报文、接收并发送数据&#xff0c;千兆网口ETH和USB2.0的底层驱动在前面的例程中也详细说明了&#xf…

常用的设计模式(单例模式、工厂模式等)

1.单例模式 概述: 在有些系统中&#xff0c;为了节省内存资源、保证数据内容的一致性&#xff0c;对某些类要求只能创建一个实例&#xff0c;这就是所谓的单例模式. 例如&#xff0c;Windows 中只能打开一个任务管理器&#xff0c;这样可以避免因打开多个任务管理器窗口而造…

Centos切换jdk版本

先安装了jdk1.8的版本&#xff0c;需要使用jdk17的版本 1.先安装jdk17&#xff0c;再配置环境变量&#xff1a; vim ~/.bashrc 2.在最后一行添加 ##这个添加的就是路径&#xff0c;一定要和自己jdk安装的路径是一致的 export JAVA_HOME/usr/lib/jvm/java-8-openjdk-amd64 3.然…

Mybatis框架超详解及运用总结

Mybatis 一、什么是Mybatils&#xff1f;二、第一个Mybatils程序2.1、创建springboot工程2.2、准备数据2.3、配置MyBatis2.4、编写SQL语句2.5、单元测试 三、JDBC四、数据库连接池五、lombok六、Mybatis基础操作6.1、删除6.2、新增6.2.1、主键返回 6.3、修改6.4、查询6.4.1、数…

【AI绘画】AI绘画的创意应用

目录 1.引言2.将AI生成的图像转化为数字艺术品2.1AI生成的画作拍卖2.2将AI生成的图像转化为雕塑 3.将AI生成的图像用于虚拟场景的创建3.1使用GAN生成虚拟人物3.2在虚拟场景中使用AI生成的图像 1.引言 当今的AI绘画技术已经发展到了让人惊艳的程度&#xff0c;不仅可以生成高质量…

【每日一题Day183】LC1187使数组严格递增 | dp

使数组严格递增【LC1187】 给你两个整数数组 arr1 和 arr2&#xff0c;返回使 arr1 严格递增所需要的最小「操作」数&#xff08;可能为 0&#xff09;。 每一步「操作」中&#xff0c;你可以分别从 arr1 和 arr2 中各选出一个索引&#xff0c;分别为 i 和 j&#xff0c;0 <…

缓存优化----SpringCache

spring cache spring Cache介绍 spring cache是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring cache提供了一层抽象&#xff0c;底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不…

springboot JWT 搭建授权服务器

目录 0 基本介绍 0.1 课程视频 0.2 架构逻辑图 0.2.1 登录JWT与授权服务器交互 0.2.2 登录成功后JWT与gateway-server交互 路由限制 1 JWT私钥公钥 1.1 安装git ->win系统右键 -> git bash here 1.2 生成私钥jks文件 1.3 用私钥jks文件解析出公钥 1.4 保存 BEGI…

造型简约的机箱,安装简单兼容性好,安钛克P20C体验

我们准备组装一台新主机的时候&#xff0c;机箱确实很重要&#xff0c;它决定了主机的整体风格和兼容性。我比较喜欢用中塔机箱&#xff0c;像是上个月我新装的主机&#xff0c;用的就是安钛克P20C&#xff0c;这款机箱的设计很简约&#xff0c;而且还有多种版本可选&#xff0…

C++——模板进阶

文章目录 &#x1f490;专栏导读&#x1f490;文章导读&#x1f337;类型模板参数&#x1f337;非类型模板参数&#x1f337;模板的特化&#x1f338;引例&#x1f338;函数模板的特化&#x1f338;类模板特化&#x1f33c;全特化 &#x1f338;偏特化&#x1f33c;部分特化&am…

【下载器篇】IDM下载器个性化设置

【下载器篇】IDM下载器个性化设置 IDM个性化设置—【蘇小沐】 文章目录 【下载器篇】IDM下载器个性化设置1.实验环境 &#xff08;一&#xff09;下载类型扩展UA默认值 &#xff08;二&#xff09;工具栏样式&#xff08;改风格&#xff09;3D Style样式 &#xff08;三&#…

2023.4.23 自注意力机制

一般都是单向量输入&#xff0c;但是如果多向量输入应该如何处理呢&#xff1f;引出自注意力机制 多向量输入可能会有多种输出&#xff0c;如果输入n个向量&#xff0c;输出n个向量表明这是sequence labeling&#xff0c;比如对于一个英文句子&#xff0c;每一个单词都判断是什…

c++11 标准模板(STL)(std::priority_queue)(二)

适配一个容器以提供优先级队列 std::priority_queue 定义于头文件 <queue> template< class T, class Container std::vector<T>, class Compare std::less<typename Container::value_type> > class priority_queue; priority_queu…

Windows下编译UHD

1.安装Visual Studio 2019,下载地址https://download.csdn.net/download/qq_36314864/87719209 2.安装cmake,下载地址https://download.csdn.net/download/qq_36314864/87719747 安装完成后记得C:\Program Files\cmake-3.22.1-windows-x86_64\bin添加到环境变量里面,或者安…

数据结构修炼:链表习题讲解!!!

题一&#xff1a;移除链表元素 我们可以看出这道题是让我们删除特定数据&#xff0c;我们可以用双指针来解这道题&#xff1a; 如果首元素为val&#xff0c;那么cur和head一起后移&#xff1a; 如果没有碰到val&#xff0c;那么就会cur后移&#xff0c;并且提前将cur传给perv&a…