C++中的模板函数和模板类

news2025/1/11 11:45:16

模板是 C++ 中的泛型编程的基础,编写与类型无关的通用代码,是代码复用的一种手段。 作为强类型语言,C++ 要求所有变量都具有特定类型,由程序员显式声明或编译器推导。 但是,许多数据结构和算法无论在哪种类型上操作,看起来都是相同的。 使用模板可以定义类或函数的操作,并让用户指定这些操作应处理的具体类型。

目录

1.函数模板

1.1模板函数的概念

1.2函数模板格式

1.3函数模板的原理

1.4函数模板的实例化

 2.类模板

2.1类模板定义格式

 2.2类模板的实例化


1.函数模板

1.1模板函数的概念

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

1.2函数模板格式

用关键字template来定义模板函数,也可以用class但是不能用struct代替class

template<typename T1 , typename T2 ,...typename Tn >

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

{

函数体

}

template<typename T>

void Swap(T& left , T& right)

{
T tep = left ;

left =right ;

right  =  tep ;

}

模板参数列表可以类比函数参数列表,也可以用class但是不能用struct代替class

1.3函数模板的原理

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

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

1.4函数模板的实例化

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

  1. 隐式类型转换:让编译器根据实参推演模板函数的实际类型
  2. 显式实例化:在函数名后的<>中指定模板参数的实际类型
//text.cpp
#include<iostream>
using namespace std;

//用函数模板生成对应的函数->模板实例化
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}


int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.0, d2 = 20.0;
	//同类型
	Add(a1, a2);
	Add(d1, d2);

/*该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
  通过实参a1将T推演为·int ,通过实参d1将T推演为double类型,但模板参数列表中只有一个T
  编译器不知道此处确定为int 还是double而报错
*/
	//不同类型
	
	//推导实例化
	cout << Add((double)a1, d1) << endl;
//a2是int类型,d2是double类型,a2强转会进行隐式类型转换
	cout << Add(a1,(int ) d1) << endl;
	//a1是int类型,d1是double类型,d1强转会进行隐式类型转换
	// 
	//显示实例化
	cout<<Add<int>(a2, d2)<<endl;
	//d2显示转换称int类型
	cout << Add<double>(a2, d2) << endl;
	//a2显示转换称double类型
	return 0;
}

对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板函数

//text.cpp
#include<iostream>
using namespace std;
//相同类型相加模板函数
template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
//不同类型相加模板函数
template<class T1,class T2>
T1 Add(const T1& left, const T2& right)
{
	return left + right;
}
//自定义Add函数
int Add(const int& x, const int& y)
{
	return x * y;
}

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.1, d2 = 20.2;


	cout<<Add(a1, a2)<<endl;
//优先调用现成的Add函数而不去模板实例化后在调用

	cout<<Add(d1, d2)<<endl;
	//走相同类型模板函数的实例化
	cout<<Add(d1, a2)<<endl;
	//走不同类型的模板实例化

	return 0;
}

 2.类模板

2.1类模板定义格式

template<class T1 , class T2 , ... ,class Tn>

class  类模板名

{
//类内成员定义
}

 2.2类模板的实例化

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

//Stack 是类名,Stack<int>才是类型

Stack<int> st1;   //int

Stack<int> st2;   //double

 

//text.cpp
#include<iostream>
using namespace std;
//相同类型相加模板函数
template<class T>
class Stack
{
public :
	Stack(int n = 4)
		:_array(new T[n])
		,_size(0)
		,_capacity(n)
	{}

	~Stack()
	{
		delete[]_array;
		_array = nullptr;
		_size = _capacity = 0;
	}

	void push(const T& x)
	{
		if (_size == _capacity)
		{
			T* tmp = new T[_capacity * 2]
				memcpy(tmp, _array, sizeof(T) * _size);
			delete[]_array;
			_array = tmp;
			_capacity *= 2;
}
		_array = [_size++] = x;
	}
private:
	T* _array;
	size_t _capacity;
	size_t _size;

};


int main()
{//类模板都是显示实例化
	Stack<int> st1;  //int
	st1.push(1);
	st1.push(2);
	st1.push(3);


	Stack<double> st2;  //double
	st2.push(1.1);
	st2.push(2.2);
	st2.push(3.3);


	return 0;
}

类模板中的函数声明与定义分离

//text.cpp
#include<iostream>
using namespace std;

template<class T>
class Stack
{
	//...

	void push(const T& x);

};

template<class T>
void Stack<T>::push(const T& x)
{
	if (_size == _capacity)
	{
		T* tmp = new T[_capacity * 2]
			memcpy(tmp, _array, sizeof(T) * _size);
		delete[] _array;
		_array = tmp;
		_capacity *= 2;
	}
	_array = [_size++] = x;
}
int main()
{
	return 0;
}

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

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

相关文章

【Java开发实训】day05——数组常见算法

目录 一、数组翻转 1.1示例代码 1.2适用场景 二、冒泡排序 2.1示例代码 2.2适用场景 三、二分查找 3.1示例代码 3.2适用场景 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo…

Elasticsearch中任务管理怎么做?

一个ES集群研发在清理数据时使用了delete_by_query&#xff0c;导致集群性能严重受影响&#xff0c;影响了正常的业务。为了快速恢复集群正常状态&#xff0c;考虑把还在进行的delete_by_query任务清除掉。 先查看当前集群的任务 GET _cat/tasks?v发现delete_by_query的任务…

Git笔记:(上传Git、Git获取文件版本、删除、统计)

目录 一、上传文件到github 1.1 配置用户名和邮箱 1.2 初始化本地仓库 1.3 添加项目目录下所有文件至本地仓库 1.4 使用如下命令加入注释提交 1.5 将本地仓库与远程仓库相连接 1.6 将本地仓库中的文件推送至指定的远程仓库中 二、git获取不同版本 2.1 git下载特定历史…

[MySQL]02 存储引擎与索引,锁机制,SQL优化

Mysql存储引擎 可插拔式存储引擎 索引是在存储引擎底层上实现的 inno DB MySQL默认存储引擎: inno DB高可靠性和高性能的存储引擎 DML操作遵循ACID模型支持事务行级锁,提高并发访问性能支持外键 约束,保证数据完整性和可靠性 MySAM MySAM是MySQL的早期引擎 特点: 不支持事…

【数据结构_C语言】归并排序—文件类型

文章目录 1.排序定义2. 代码实现 1.排序定义 内排序&#xff1a;数据量相对少一些&#xff0c;可以放到内存中排序。 外排序&#xff1a;数据量较大&#xff0c;内存中放不下&#xff0c;数据放到磁盘文件中&#xff0c;需要排序。 归并排序&#xff1a; 2. 代码实现 void…

基于CNN-BiLSTM的数据回归预测

代码原理 基于CNN-BiLSTM的数据回归预测是一种结合卷积神经网络&#xff08;CNN&#xff09;和双向长短期记忆网络&#xff08;BiLSTM&#xff09;的混合模型&#xff0c;用于处理和预测时间序列数据。以下是该方法的简单原理及流程&#xff1a; 原理 &#xff08;1&#xf…

OSGB整体或自定义区域转换为3DTiles

工具 OSGB源数据灵易智模倾斜摄影编辑平台(下称OPEditor) 操作步骤 打开倾斜摄影 打开软件&#xff08;登录即注册&#xff0c;直接用手机号登录&#xff09;使用OPEditor打开OSGB原始倾斜数据&#xff0c;将会看到如下页面 整体导出为3DTiles 在右侧节点树上鼠标右键点…

“为你写诗”,与ai“推敲”码字:第一次在严谨的csdn发布只有“思绪”没有代码的笔记(ai对话实录)

与ai“推敲”码字&#xff0c;第一次在严谨的csdn发布只有“思绪”没有代码的笔记(ai对话实录)。 (笔记模板由python脚本于2024年07月22日 21:13:08创建&#xff0c;本篇笔记适合本文无关代码&#xff0c;爱思考穷探究的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&…

力扣21-30题(数学的简单的结束和数组的前几道)

20240721 1.题和解析693. 交替位二进制数405. 数字转换为十六进制数171 excel 表序列号 从这之后的是数组了2011. 执行操作后的变量值1929. 数组串联1720. 解码异或后的数组异或解析&#xff1a;2574. 左右元素和的差值101. 对称二叉树LCP 06. 拿硬币1365. 有多少小于当前数字的…

org.springframework.context.ApplicationContext发送消息

1、创建消息的实体类 package com.demo;/*** 监听的实体类**/ public class EventMessage {private String name;public EventMessage(String name) {this.name name;}public String getName() {return name;}public void setName(String name) {this.name name;} }2、创建消…

three.js NDC空间转视图空间(getViewPosition)

three.js NDC空间转视图空间 NDC空间转视图空间, 比较常用。很多效果依赖于此。 包括: GTAOShaderReflectorForSSRPassSSRShader 下面看一下它的庐山真面目。 1、计算clipW 视图空间(view) 应用投影矩阵后转换到 剪裁空间(clip)。 [ A 0 B 0 0 C D 0 0 0 E F 0 0 − 1 0 ]…

Truenas scale 配置 Official Zerotier 并设置一直固定Zerotier IP

Zerotier 安装 TrueNAS Scale -> Apps -> Discover Apps -> 搜索 Zerotier 并安装Netwoek 中填入你 zerotier 网页中的的 Network IDAuto Token (API key) zerotier网页的 Account -> API Access Tokens -> New Tokenidentity.secret 和 identity.public 通过 …

国际化技术参考

一、概述 国际化就是用户可以选择对应的语言,页面展示成对应的语言; 一个系统的国际化按照信息的所在位置,可以分为三种国际化信息: 前端页面信息后端提示信息数据库的字典类信息二、前端页面国际化 使用i18n库实现国际化 i18n国际化库思路:通过jquery或者dom操作拿到需…

【动态规划】打家劫舍

动态规划的四个解题步骤&#xff1a; 1、定义子问题 2、写出子问题的递推关系 3、确定dp数组的计算顺序 4、空间优化&#xff08;可选&#xff09;上一篇博客学的有点杂乱&#xff0c;这一篇从解题步骤方面整理一下动态规划这一章。 打家劫舍&#xff08;难度&#xff1a;中等…

C++进阶中继承的全部主要内容

小编在学习完C中继承的内容之后&#xff0c;觉得继承的内容很重要&#xff0c;所以今天给大家带来的内容就是继承的主要内容&#xff0c;今天的内容包括继承的定义与语法&#xff0c;继承方式与权限&#xff0c;基类和派生类的类型转换赋值&#xff0c;继承中的隐藏&#xff0c…

数据跨境法案:美国篇下

数据跨境法案美国篇下主要介绍2018年《出口管制改革法案》(ECRA)、2018 年《外国投资风险审查现代化法案》(FIRRMA) 和《强化海外关键出口国家框架法》&#xff08;ENFORCE&#xff09;。其中 ECRA法案和 FIRRM 法案作为2019财年约翰S麦凯恩国家国防授权法&#xff08;NDAA&…

MySQL定时备份数据,并上传到oss

1.环境准备 1.安装阿里云的ossutil 2.安装mysql 2.编写脚本 脚本内容如下 #!/bin/bash # 数据库的配置信息&#xff0c;根据自己的情况进行填写 db_hostlocalhost db_usernameroot db_passwordroot db_namedb_root # oss 存贮数据的bucket地址 bucket_namerbsy-backup-buck…

开源发票识别InvoiceNet项目Windows部署踩坑记(1)

今天安装在github上的InvoiceNet开源项目&#xff0c;准备对它进行测试&#xff0c;安装过程出现了一些问题&#xff0c;做个记录&#xff0c;给遇到兄弟爬坑。 第一个问题&#xff0c;conda的问题&#xff0c; 这是另外一个包管理器&#xff0c;不仅仅可以管理python的虚拟…

如何通过smtp设置使ONLYOFFICE协作空间服务器可以发送注册邀请邮件

什么是ONLYOFFICE协作空间 ONLYOFFICE协作空间&#xff0c;是Ascensio System SIA公司出品的&#xff0c;基于Web的&#xff0c;开源的&#xff0c;跨平台的&#xff0c;在线文档编辑和协作的解决方案。在线Office包含了最基本的办公三件套&#xff1a;文档编辑器、幻灯片编辑…

XXE:XML外部实体引入

XXE漏洞 如果服务器没有对客户端的xml数据进行限制&#xff0c;且版本较低的情况下&#xff0c;就可能会产生xxe漏洞 漏洞利用流程 1.客户端发送xml文件&#xff0c;其中dtd存在恶意的外部实体引用 2.服务器进行解析 3.服务器返回实体引用内容 危害&#xff1a;任意文件读…