c++模板的简单认识

news2025/1/31 8:13:34

 

 

文章目录

  • 前言
  • 一.泛型编程
  •      函数模板
  •      模板参数的匹配原则
  •      类模板
  • 总结

 


前言

ADD函数很好写,但是如果我们要有int类型的,double类型的,char类型的等等各种类型,难道要写这么多不同的ADD函数吗,这么写简直太麻烦了,所以有了泛型编程的概念。


 

一、泛型编程

实现一个通用的ADD函数有很多办法,就比如函数重载,但是函数重载又有很多的缺点,比如:

1.重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。

2.代码的可维护性比较低,一个出错可能所有的重载都出错。

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

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

函数模板

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

函数模板格式:

template<typename p1,typename p2........>

注意: typename 用来定义模板参数 关键字也可以使用 class(切记:不能使用struct代替class)
template <class T>
void Swap(T& d1, T& d2)
{
	T tmp = d1;
	d1 = d2;
	d2 = tmp;
}
int main()
{
	int a = 10, b = 50;
	Swap(a, b);

	double c = 2.36, d = 6.15;
	Swap(c, d);
	return 0;
}

3b40aac6911a4438bf22fb7ba793e11c.png

那么上图中的两次调用Swap函数是同一个函数吗?这里不是同一个函数,我们先来验证一下:

2a078b1112d14e37b9b44383c42af471.png f3a3c429bf594036a65ca23a55f30a33.png

 通过汇编代码我们发现两个函数并不是同一个,他们有着不同的地址。这是因为模板就像是印刷的模具一样,生成的函数就是印刷出来的书,我们看的是书并不是印刷的板,每本书用的印刷的板都是一样的但是书中的内容是不一样的。

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

 e10acf4bb36241c9b20e04ae82d91700.png

 下面我们来看一些关于模板的小细节:

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

首先上面的代码是可以正常编译的,那么如果写成下面这样呢?

6e2c58f90b304e4fa0c50c06917a0a23.png

这里有两种解决方式,一种是强制类型转换,一种是显式实例化。

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.22, d2 = 20.32;
	//实参传递给形参,自动推演模板类型
	cout << Add(a1, (int)d1) << endl;
	cout << Add(d1, d2) << endl;
	//显示实例化
	cout << Add<int>(a1, d2) << endl;
	cout << Add<double>(a1, d1) << endl;
	return 0;
}

ebf3f3fbd892496faaa16a9d6b77c830.png

 在函数名后加<(需要的类型)>就可以完成显式实例化,编译器直接以显式的类型去计算。

模板参数的匹配原则

// 专门处理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<int>(1, 2); // 调用编译器特化的Add版本
}
int main()
{
	Test();
	return 0;
}

87d7c08fce4b43aeb6f5d2d9b3e91c6a.png

 我们可以看到上面代码中有两个Add函数,当他们类型都为int的时候为什么没有函数重定义呢?

这是因为一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

586ed4cd9714418d81e70ccdb1c85a89.png

那么像上图这样的情况编译器会调用哪个呢?答案是第一个,因为对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的一个函数,那么将选择模板。

什么意思呢?就是说已经存在一个能用的函数了编译器就不会花时间去实例化一个相同的函数,而是调用那个已经存在的函数。

如果我们必须要调用那个模板有什么方法吗?

caced6abeec24b7f9107748a648f8010.png 我们直接在函数名后显示实例化就会调用模板了。

类模板 

template<class T>
class Stack
{
public:
	Stack(int capacity = 4)
	{
		_a = new T[capacity];
		_top = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		delete[] _a;
		_a = nullptr;
		_top = _capacity = 0;
	}
paivate:
	T* _a;
	size_t _top;
	size_t _capacity;
};
int main()
{
	Stack<int> sl;
	Stack<double> st;
	return 0;
}

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

注意:模板的声明和定义分开与普通类不一样,如下图:

b832acdbfdc040a6bff91e7d6e533c99.png

9cb58e09c3074b2d85fc4be48a85c823.png 模板的声明和定义分离只限于在一个文件中,如果声明和定义在两个不同的文件会出现链接错误。

0472bfbf0be34f47922594518edffe59.png

模板的类创建对象必须显示实例化在类名后面加<>确定其类型。 

 


总结

模板的出现让我们在写一些代码相同但是类型不同的函数或者类的时候方便了很多,以前这些都是由我们自己写出来的,有了模板就可以由编译器去做这件事,并且编译器做的比我们更好,因为人写总是会出现一些粗心的错误,编译器却不会。

 

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

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

相关文章

Linux:基于bufferevent epoll tcp服务器代码

基于bufferevent epoll tcp服务器代码: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <event2/event.h> #include <event2/buffer…

Excel/Word的一些快捷操作整理

Excel/Word的一些快捷操作整理 1. 给Word文件导入目录 前提&#xff1a;大致内容已经定稿&#xff0c;文章中各标题分级明确&#xff0c;最好各级标题字体大小设置不一样。 步骤&#xff1a;在头部导航栏&#xff0c;选择**“引用”–“目录”**&#xff0c;根据自己需求选择其…

KDJB1200六相继电保护测试仪

一、概述 KDJB1200继电保护测试仪是在参照电力部颁发的《微机型继电保护试验装置技术条件(讨论稿)》的基础上&#xff0c;广泛听取用户意见&#xff0c;总结目前国内同类产品优缺点&#xff0c;充分使用现代新的的微电子技术和器件实现的一种新型小型化微机继电保护测试仪。可…

DataWhale 大数据处理技术组队学习task3

四、分布式数据库HBase 1. 产生背景 1.1 Hadoop的局限性 优点&#xff1a;存储结构化、半结构甚至非结构化的数据&#xff0c;是传统数据库的补充&#xff0c;是海量数据存储的最佳方法。缺陷&#xff1a; 只能进行批处理&#xff0c;并且只能以顺序的方式访问数据。&#x…

【C++】-- 异常

目录 C语言传统的处理错误的方式 C异常概念 异常的使用 异常的抛出和捕获 自定义异常体系 异常的重新抛出 异常安全 异常规范&#xff08;C期望&#xff09; C标准库的异常体系 异常的优缺点 C异常的优点 C异常的缺点 总结 C语言传统的处理错误的方式 传统的错误…

zookeeper单机部署

一.下载zookeeper压缩包 二.上传解压安装包到/data/zookeeper目录&#xff0c;并解压 tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz 三.修改配置文件 cd apache-zookeeper-3.5.10-bin/conf mv zoo_sample.cfg zoo.cfg vi zoo.cfg 修改为如下&#xff1a; dataDir/data/zooke…

【研究空间复用及函数调用问题】

本篇总结函数调用过程会存在的一些奇怪现象&#xff0c;空间复用问题&#xff0c;其实本质上涉及函数调用的底层原理&#xff0c;理解函数栈帧的创建和销毁这样的问题直接迎刃而解。1.空间复用问题案例1案例22.函数调用过程不清晰问题案例33.总结1.空间复用问题 案例1 我们先…

程职场人必备微软出品的实用小工具

系统增强工具PowerToys 下载地址&#xff1a;https://github.com/microsoft/PowerToys 什么是 Windows 系统中&#xff0c;最好的辅助工具&#xff1f; PowerToys 一定可以获得提名。PowerToys 是一款来自微软的系统增强工具&#xff0c;就像是一个神奇的系统外挂&#xff0c;…

精确控制 AI 图像生成的破冰方案,ControlNet 和 T2I-Adapter

ControlNet 和 T2I-Adapter 的突破性在哪里&#xff1f;有什么区别&#xff1f;其它为 T2I 扩散模型施加条件引导的相关研究ControlNet 和 T2I-Adapter 的实际应用效果如何&#xff1f;使用体验上&#xff0c;跟 SD原生支持的 img2img 有什么区别&#xff1f;ControlNet 在插画…

电商数据采集——2022年中国手机行业数据浅析

据国家统计局数据显示&#xff0c;2022年12月&#xff0c;国内手机产量当期值为14310.3万台&#xff0c;同比下降18.4%&#xff1b;累计值为156080万台&#xff0c;同比下降6.2%。 据中国信通院数据显示&#xff0c;2022年12月&#xff0c;国内市场手机出货量2786.0万部&#x…

F.pad() 函数

F.pad() 对tensor 进行扩充的函数。 torch.nn.functional.pad (input, pad, mode‘constant’, value0) input&#xff1a;需要扩充的 tensor&#xff0c;可以是图像数据&#xff0c;亦或是特征矩阵数据&#xff1b;pad&#xff1a;扩充维度&#xff0c;预先定义某维度上的扩充…

内存泄露定位手段(c语言hook malloc相关方式)

如何确定有内存泄露问题&#xff0c;如何定位到内存泄露位置&#xff0c;如何写一个内存泄漏检测工具&#xff1f; 1&#xff1a;概述 内存泄露本质&#xff1a;其实就是申请调用malloc/new&#xff0c;但是释放调用free/delete有遗漏&#xff0c;或者重复释放的问题。 内存…

搞懂事件——C# 的event的机制深度理解

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:无尽的折腾后,终于又回到了起点,工控,我来了 !1. 前言 为什么忽然对Event感兴趣了? 因为进入Web时代以后,很少使用它了,忽然想起这个知识点,…

STM32 CAN波特率计算

STM32 CAN波特率计算简介CAN总线收发&#xff0c;中断方式接收配置代码部分reference简介 CAN通信帧共分为数据帧、远程帧、错误帧、过载帧和帧间隔&#xff0c;本文这里以数据帧为例。 显性电平对应逻辑0&#xff0c;CAN_H和CAN_L之差为2.5V左右。而隐性电平对应逻辑1&#x…

元宇宙对营销方式的影响

营销方式的变化通常伴随着技术的发展。我们已经看到营销方式从印刷媒体、电视、广播到互联网的转变。而现在&#xff0c;我们又处在下一个营销方式大跃进的风口浪尖上。 关于元宇宙及其潜在的变革性影响&#xff0c;人们已经讨论了很多。虽然与元宇宙相关的大多数东西在很大程…

使用 husky 进行基础代码审查

在日常提交 PR 的过程中&#xff0c;我们提交的文件不应该有例如 console、debugger、test.only 等调试语句&#xff0c;这会影响到线上代码。那每次提交之前都检查似乎又像是一个繁琐的工作&#xff0c;如果有个工作能代替我们检查我们提交的代码&#xff0c;让不能提交到线上…

Linux 文件相关操作

文件相关操作 编辑文件 命令&#xff1a; vi 文件名 然后输入i进入编辑模式 编辑完成后输入esc退出编辑 输入:wq保存即便目录下没有这个文件&#xff0c;也可以想使用vi 文件名进行编辑&#xff0c;保存退出后会创建这个文件 查看文件内容 命令&#xff1a; cat 文件名复…

UDP报文详解

目录 &#x1f433;今日良言:走好选择的路&#xff0c;别选择好走的路&#xff0c;你才能拥有真正的自己。 &#x1f43c;一、UDP协议特点 &#x1f43c;二、UDP协议段格式详解 &#x1f433;今日良言:走好选择的路&#xff0c;别选择好走的路&#xff0c;你才能拥有真正的自…

PointNet++训练自己的数据集(附源码)

本文针对PointNet强大的三维点云分类功能&#xff0c;详细讲解怎么训练自己的数据集&#xff0c;在此之前&#xff0c;需要确保已经能够跑通源码的训练和测试&#xff0c;如果没有&#xff0c;请参考PointNet的源码运行。数据放置1.1. 在mytensor_shape_names.txt中配置自己的分…

LeetCode-40.组合总和II

目录题目思路回溯法题目来源 40.组合总和II 题目思路 这道题目和39.组合总和如下区别&#xff1a; 本题candidates 中的每个数字在每个组合中只能使用一次。本题数组candidates的元素是有重复的&#xff0c;而39.组合总和是无重复元素的数组candidates 为了理解去重我们来举…