模板(初阶)

news2024/11/26 8:55:22

目录

  • 一、泛型编程
  • 二、函数模板
    • 2.1 函数模板的概念
    • 2.2 函数模板的格式
    • 2.3 函数模板的原理
    • 2.4 函数模板的实例化
    • 2.5 模板参数的匹配原则
  • 三、类模板
    • 3.1 类模板的定义格式
    • 3.2 类模板的实例化

一、泛型编程

如何实现一个通用的Swap函数

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}
void Swap(double& x, double& y)
{
	double tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d , b=%d\n", a, b);
	Swap(a, b);
	printf("交换后:a=%d , b=%d\n", a, b);

	double c = 12.5;
	double d = 24.2;
	printf("交换前:a=%.2lf , b=%.2lf\n", c, d);
	Swap(c, d);
	printf("交换后:a=%.2lf , b=%.2lf\n", c, d);

	return 0;
}

像上面那样使用函数重载虽然可以不知不觉地实现不同的参数类型达到一样的交换效果,但是可以看到,Swap函数除了参数类型不同,其他的运算逻辑都是一样的。
函数重载有两个不好的地方:一是代码的复用性低,只要有新的类型出现就要再重载一个函数,代码冗余太严重。二是维护成本较高,一个重载函数出错就会导致所有的重载函数都出错,修改成本太大。

那么我们能否给编译器一个模子,让编译器根据不同的类型利用该模子来生成一份对应的代码呢?基于这样的问题,C++就出现了模板,之后又推出了泛型编程。

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

二、函数模板

2.1 函数模板的概念

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

2.2 函数模板的格式

template<class T1,class T2,class T3…>
返回值 函数名(参数列表){函数体}

例如Swap函数:

template <class T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("交换前:a=%d , b=%d\n", a, b);
	Swap(a, b);
	printf("交换后:a=%d , b=%d\n", a, b);

	double c = 12.5;
	double d = 24.2;
	printf("交换前:a=%.2lf , b=%.2lf\n", c, d);
	Swap(c, d);
	printf("交换后:a=%.2lf , b=%.2lf\n", c, d);

	return 0;
}

在这里插入图片描述
由上图可以看出,写了一个Swap函数模板之后,无论需要交换什么类型的数据,都不用手动再写同样逻辑的代码,而是编译器会自动生成一份对应的代码完成数据的交换,

2.3 函数模板的原理

函数模板本身并不是一个函数,而是一个模具,是编译器使用特定方式产生具体类型函数的模具。就好比我们工厂在制造月饼的时候所用的月饼模,它本身并不是月饼,只不过把材料放到这个模具之后就能形成月饼的形状。换句话说其实模板就是将本来应该我们做的重复的事情交给了编译器做。
在这里插入图片描述
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然后产生一份专门处理int类型的代码,对于其他类型也是如此。

2.4 函数模板的实例化

用不同类型的参数使用函数模板生成对应的函数,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
1、隐式实例化:让编译器根据实参推导出模板参数的实际类型。
2、显式实例化:在函数名后的<>中指定模板参数的实际类型。

template <class T>
T Add(const T& x,const T& y)
{
	return x + y;
}

int main()
{
	隐式实例化,通过传实参a、b给Add函数模板,自动生成一份
	int类型的Add函数代码
	int a = 10;
	int b = 20;
	int sum1 = Add(a, b);
	cout << sum1 << endl;

	隐式实例化,通过传实参c、d给Add函数模板,自动生成一份
	double类型的Add函数代码
	double c = 12.5;
	double d = 24.2;
	double sum2 = Add(c, d);
	cout << sum2 << endl;

	//Add(a, d);
	//这样写是错误的,因为该函数模板只有一个模板参数T,而a的类型是
	//int,d的类型是double;编译器无法确定这里的T应该推导为int还是double从而报错
	//在模板中,编译器不会进行类型转换
	//这时解决方法有两个:

	//1、强制类型转换 
	int sum3 = Add(a, (int)d);
	cout << sum3 << endl;

	//2、显式实例化
	//如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法成功
	// 转换编译器将会报错。
	//例如这里的c是double类型,编译器会把它隐式转换成int类型再
	//利用模板实例化出int类型的Add函数,再调用
	int sum4 = Add<int>(a, c);
	cout << sum4 << endl;

	return 0;

}

2.5 模板参数的匹配原则

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

三、类模板

3.1 类模板的定义格式

下面是一个简单的作为示例的Stack类:

//注意:Stack不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template <class T>
class Stack
{
public:
	Stack(int capacity = 10)
		:_a(new T[capacity])
		,_capacity(capacity)
		,_top(0)
	{}

	~Stack()
	{
		if (_a)
		{
			delete[] _a;
			_a = nullptr;
		}
		_capacity = _top = 0;
	}

	//Push函数类中声明,类外定义
	void Push(const T& x);

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

// 注意:类模板中函数放在类外面定义时,需要加模板参数列表
//并且这个模板参数列表只在这个Push函数内有效,即每定义一个
//成员函数,都需要写一遍模板参数列表(谨记)
template <class T>
void Stack<T>::Push(const T& x)
{
	_a[_top] = x;
	_top++;
}

int main()
{
	//实例化成存放int类型数据的栈
	Stack<int> st1;
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);

	//实例化成存放double类型的栈
	Stack<double> st2;
	st2.Push(1.2);

	return 0;
}

3.2 类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型(int,double,char或者自定义类型等)放在<>中即可,类模板名字不是真正的类,相当于一张图纸,而实例化的结果才是真正的类,实例化得到的具体的类才能用来定义对象。

下面的Stack是类名,Stack<int>和Stack<double>才是类型
即Stack是类模板,Stack<int>才是实例化出来的具体的类
Stack<int> st1;
Stack<double> st2;

以上就是今天我要跟大家分享的模板初阶的内容,这里并不是模板的所有内容哦,后面还会有模板进阶的部分哦。好了,今天的内容你学会了吗?如果感到有所收获,那么点亮一下小心心,再点点关注呗,后期还会持续更新C++相关的知识哦,我们下期见!!!!

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

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

相关文章

chatgpt赋能Python-pythonapp自动化

Python App自动化&#xff1a;优化SEO的终极解决方案 随着互联网的发展&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;变得日益重要。对于任何网站或应用程序开发人员来说&#xff0c;SEO应该是一个非常重要的考虑因素。为了帮助开发人员和企业提高其在线可见性&#x…

Squid代理服务器应用

在web架构中&#xff0c;用户一般进入负载均衡层&#xff0c;通过调度来访问web应用层&#xff0c;但是如果访问量太大&#xff0c;并发量较高&#xff0c;web应用层会吃不消&#xff0c;我们把静态资源、经常要访问的资源放入缓存&#xff0c;用户直接访问缓存层&#xff0c;加…

解析使用FPGA逻辑实现FIR滤波器的几种架构

有限脉冲响应(finite impulse response&#xff0c;FIR)数字滤波器 一、FIR数字滤波器理论介绍 FIR滤波器的实质就是输入序列与系统脉冲响应的卷积&#xff0c;即&#xff1a; 其中&#xff0c;N为滤波器的阶数&#xff0c;也即抽头数&#xff1b;x(n)为第n个输入序列&#xff…

人工智能轨道交通行业周刊-第45期(2023.5.15-5.21)

本期关键词&#xff1a;动车洗澡、热备列车、火车司机室、无缝线路、图像分割、自动标注 1 整理涉及公众号名单 1.1 行业类 RT轨道交通人民铁道世界轨道交通资讯网铁路信号技术交流北京铁路轨道交通网上榜铁路视点ITS World轨道交通联盟VSTR铁路与城市轨道交通RailMetro轨道…

Linux开发工具:yum和vim的使用

目录 一. Linux下的软件 1.1 软件安装的三种方法 1.2 采用yum安装软件 1.3 yum源的问题 二. vim开发工具的使用 2.1 vim的三种基本模式 2.2 命令模式下vim的常用指令 2.2.1 定位相关指令 2.2.2 光标移动相关指令 2.2.3 插入相关指令 2.2.4 复制粘贴相关指令 2.2.5 替…

Tauri应用开发(三):自定义拖拽区域

1. 自定义拖拽&#xff1a;data-tauri-drag-region tauri默认的顶部可拖拽&#xff0c;有时候我们不需要这个拖拽&#xff0c;或者需要自定义拖拽区域时&#xff0c;就需要通过tauri提供的data-tauri-drag-region属性来自定义拖拽区。 ![在这里插入图片描述](https://img-blog…

基于Python的图书信息管理系统

1引言 进入21世纪以来&#xff0c;信息技术从根本上推动了图书馆的飞速发展&#xff0c;计算机和计算机管理系统已成为图书馆进行图书管理的主要设备和系统。虽然目前很多大型的图书馆已经有一整套比较完善的管理系统&#xff0c;但是在一些中小型的图书馆中&#xff0c;大部分…

【Python 虚拟环境创建】解决遇到的问题并在vscode上测试

目录 一、前提准备 二、python虚拟环境创建 解决问题&#xff1a;‘virtualenv’/‘mkvirtualenv‘ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 解决问题&#xff1a;pycharm终端提示无法加载文件 E:\software\python_pycharm\venv\Scripts\activat…

Kuberntes云原生实战09 Kubernetes高可用安装小结

大家好,我是飘渺。 今天咱们继续更新Kubernetes云原生实战系列,本节文章是我们在安装过程中可能会遇到的问题以及解决方法。(都是我踩过的坑,你们大概率也会遇到~) 1. kubesphere平台无法使用kubectl命令行工具 问题现象 如果你给你的KubeSphere在Nginx上配置了域名访…

【2023 雷泽杯 · Misc】png的秘密

一个关于png结构的题目 一、题目 一张打不开的png文件&#xff0c;唉。 二、解题思路 少了头&#xff0c;就给他加上。我比较笨&#xff0c;还是萌新&#xff0c;采用导出16进制&#xff0c;添加后&#xff0c;010editor导入16进制。 添加之后&#xff0c;顺眼多了。然后用png…

阿里云服务器 之 mqtt服务器搭建及使用

本文主要是对mqtt的学习使用&#xff0c;其中服务器是基于阿里云服务器的mqtt功能&#xff0c;客户端使用的是mqttx软件。 一、服务器部分搭建说明 1、如果是首次使用&#xff0c;则需要经过注册与认证的步骤。 2、找到"产品与服务"-->"物联网平台"&…

DAY 60 mysql的备份与恢复

数据备份的重要性 备份的主要目的是灾难恢复。 在生产环境中&#xff0c;数据的安全性至关重要。 任何数据的丢失都可能产生严重的后果。 造成数据丢失的原因&#xff1a; 程序错误人为操作错误运算错误磁盘故障灾难&#xff08;如火灾、地震&#xff09;和盗窃 数据库备份…

redis 高可用与优化

一、Redis高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提…

成绩管理系统

系列文章 任务28 成绩管理系统 文章目录 系列文章一、实践目的与要求1、目的2、要求 二、课题任务三、总体设计1.存储结构及数据类型定义2.程序结构3.所实现的功能函数4、程序流程图 四、小组成员及分工五、 测试读入数据浏览全部信息增加学生信息保存数据删除学生信息修改学生…

加密与解密 基础篇/win API/小端序大端序

1.1加密和解密的概念 是侧重于windows 的加密保护和解密技术 首先我们先要了解 软件逆向工程 可执行程序->反编译->源代码这就是逆向工程 接着 逆向分析技术是什么 静态调试 和动态调试 主要分为这俩类1.通过软件的执行 来分析程序 我们可以通过阅读程序的执行 或…

这个Set接口真牛逼

偶然间看到 java.util 包下的 Set 接口&#xff0c;看着好搞笑哈哈哈哈哈哈哈 包括了如下几个方法&#xff1a; 创建包含0个元素的不可修改的Set集合创建包含1个元素的不可修改的Set集合创建包含2个元素的不可修改的Set集合创建包含3个元素的不可修改的Set集合创建包含4个元素…

ROS:laser激光雷达数据格式、发送laser数据、订阅laser数据

一.激光雷达数据格式 图片来源&#xff1a;ROS-订阅与处理激光雷达scan话题_ros激光雷达数据处理_zhhao1326的博客-CSDN博客 # 测量的激光扫描角度&#xff0c;逆时针为正 # 设备坐标帧的0度面向前&#xff08;沿着X轴方向&#xff09; Header header # Header也是一…

Java学习路线(8)——面向对象基础(2)

一、static关键字 概念&#xff1a; static是静态的意思&#xff0c;可以修饰成员变量和成员方法。当修饰成员变量时&#xff0c;在内存中只存储一份&#xff0c;可以被共享访问、修改。当修饰成员方法时&#xff0c;可以被共享访问&#xff0c;也被称为公共方法。 静态成员变…

【linux网络】防火墙规则二:SNAT策略与DNAT策略

防火墙规则 一、SNAT策略1.1SANT的原理与应用1.2SNAT实验 二、DNAT策略2.1DNAT的原理与应用2.2DNAT实验 三、Linux的抓包工具tcpdump3.1补充知识 四、防火墙规则的备份和还原 一、SNAT策略 1.1SANT的原理与应用 SNAT 应用环境&#xff1a;局域网主机共享单个公网IP地址接入In…

2023.05.21 学习周报

文章目录 摘要文献阅读1.题目2.背景3.现存问题和解决方法4.方法4.1 Variational mode decomposition (VMD)4.2 Bidirectional LSTM 5.实验5.1 数据标准化5.2 评价指标5.3 实验过程及结果 6.结论和展望 优劣解距离法有限元1.求解一个简单的传热问题2.有限元如何实现 总结 摘要 …