C++泛型编程——模板(初识)

news2024/11/25 16:36:38

C++泛型编程——模板(初识)

文章目录

  • C++泛型编程——模板(初识)
  • 1. 泛型编程的概念
  • 2. 模板
    • 2.1 模板格式
    • 2.2 函数模板
      • 2.3 函数模板的实例化
        • 2.3.1 隐式(推演)实例化
        • 2.3.2 显式实例化
    • 2.3 类模板
    • 3. 模板的本质

本章思维导图:
在这里插入图片描述注:本章思维导图对应的 xmind.png文件都已同步导入至 资源


1. 泛型编程的概念

在C++中,如果我们不借助库函数,要实现两个数据的交换函数swap,由于要考虑到数据类型的多样性,我们难免要将swap函数重载很多次,例如:

void swap(int& num1, int& num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

void swap(char& num1, char& num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}
k'j
void swap(double& num1, double& num2)
{
	int temp = num1;
	num1 = num2;
	num2 = temp;
}

//…………………………

swap函数的函数体基本相同,只有交换数据的类型不同,但就是由于这个小小的不同迫使我们产生很多冗余代码,使生产效率变得低下

为了解决这一问题,C++就支持了泛型编程这一概念:

允许我们用一个通用的代码模板来处理不同类型数据

在C++中,泛型编程就是靠模板来实现的

2. 模板

2.1 模板格式

基本格式为:

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

  • template为模板的关键字
  • <>里面的即模板参数,代表一个数据类型
  • typename可以用class替代

2.2 函数模板

在这里插入图片描述

基本格式为:

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

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

例如:

//定义一个函数模板swap
//T泛指所有类型

template <typename T>
void swap(T& num1, T& num2)
{
	T temp = num1;
	num1 = num2;
	num2 = temp;
}

注意:

当模板函数的声明和定义不能分布在不同的文件

2.3 函数模板的实例化

用不同的类型使用函数模版生成一个具体的函数这一过程叫做函数模板的实例化,函数模板的实例化有以下两种方法:

2.3.1 隐式(推演)实例化

推演实例化——让编译器根据实参推演模板参数的实际类型

例如:

template <typename T>
void swap(T& num1, T& num2)
{
	T temp = num1;
	num1 = num2;
	num2 = temp;
}


int main()
{
	int a = 1, b = 2;
	double a1 = 1.0, b1 = 2.0;

	swap(a, b);	//实例化函数模板为swap(int& num1, int& num2),并进行调用
	swap(a1, b1);	//实例化函数模板为swap(double& num1, double& num2),并进行调用

	return 0;
}

需要注意:
如果该函数模板的模板参数只有一个,那么进行推演实例化时,传入的实参的类型就只能有一个(即模板不允许自动类型转换

例如:

template <typename T>
void swap(T& num1, T& num2)
{
	T temp = num1;
	num1 = num2;
	num2 = temp;
}

int main()
{
	int a = 1;
	double b = 2.0;
	swap(a, b);

	return 0;
}

//会报错:
// “swap”: 未找到匹配的重载函数
// “void swap(T &,T &)”: 模板 参数“T”不明确

为了避免这个问题,一种解决方式就是增多模板参数

template <typename T1, typename T2>
void swap(T1& num1, T2& num2)
{
	T1 temp = num1;
	num1 = num2;
	num2 = temp;
}

int main()
{
	int a = 1;
	double b = 2.0;
	swap(a, b);

	return 0;
}

一种方法是使用强制类型转换,使传入的类型相同。但这个方法也有一个需要注意的点:如果函数模板的形参为引用类型,但是没有被const修饰,那么就不能用强制类型转换来实现推演实例化:

template <typename T>
void swap(T& num1, T& num2)
{
	T temp = num1;
	num1 = num2;
	num2 = temp;
}

int main()
{
	int a = 1;
	double b = 2.0;

	swap(a, (int)b);
 //(int)b涉及数据类型的转换,因此产生了一个临时变量,而临时变量具有常性(const),
 //被const修饰的引用权限不能被放大,因此无法转换为没有被const修饰的形参T& num

	return 0;
}

还有一种常用的方法就是使用显式实例化

2.3.2 显式实例化

显式实例化——在函数名后的<>中指定模板参数的实际类型

注意:使用显式实例化同样需要注意引用权限不能提升的问题

例如:

template <typename T>
T Add(const T& num1, const T& num2)
{
	return num1 + num2;
}

int main()
{
	int a1 = 1, b1 = 2;
	double a2 = 2.0, b2 = 4.99;

	int ret1 = Add<int>(a1, a2);
	double ret2 = Add<double>(b1, b2);

	return 0;
}

2.3 类模板

在这里插入图片描述

基本格式

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

class 类模板名 {};

例如:

//定义一个类模板stack
//该stack可以存储所有类型

template <class T>
class stack
{
public:
	stack(int capacity = 3)
	{
		_a = new T[capacity];
		_capacity = capacity;
		_top = 0;
	}

	void push(T val) {}

	//…………

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

类模板只能显示实例化,其基本格式为:

类模板名 <数据类型> 对象名

例如对于上面的类模板stack

stack<int> st1;
stack<double> st2;

成员函数声明和定义分离

template <class T>
class stack
{
public:
	stack(int capacity = 3)
	{
		_a = new T[capacity];
		_capacity = capacity;
		_top = 0;
	}

	void push(T val);

	//…………

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

//当声明和定义分离时,需要制定成员函数所在类的类型
//类模板的类模板名不是类名,类模板名<数据类型>才是类类型
//同样,成员函数的声明和定义不能分在两个不同的文件
template <class T>
void stack<T>::push(T val) {}

3. 模板的本质

  • 和类实例化对象类似,我们不能将类看成是一个具体的对象,它只是一个不占据空间的蓝图

  • 同样,我们也不能将函数模板和类模板看成是一个具体的函数和类,他们也只是实例化一个具体函数和类的模具

  • 只有我们使用一个或多个具体的数据类型用模板实例化时,才会形成一个具体的函数和类。

在这里插入图片描述

如上图所示, 在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。因此实际上,我们没写的冗余代码,编译器都替我们完成了,是编译器在替我们负重前行。

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

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

相关文章

【教学类-36】八等分格子-A4竖版-4条(制作皇冠、戒指)

背景需求&#xff1a; 最近在大四班孩子中间普及铅画纸制作“方盒”的活动&#xff0c;目前进展到使用三条8等分的长条纸&#xff0c;制作一个“坚硬的、不漏底”的方盒。 实验后&#xff0c;我想试试如果缩小纸条长宽&#xff0c;是不是可以做“迷你”纸盒。 目的&#xff…

为什么别人年薪30W+?同样为测试人,“我“的测试之路...

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

可变形卷积 DeformConv2d

可变性卷积 前言为什么要用DConv普通卷积和与可变形卷积计算过程普通卷积计算过程Pytorch官方API可变形卷积计算过程 参考资源 前言 可变形卷积即DCN&#xff08;缩写取自Deformable ConvNets&#xff09;提出于ICCV 2017的paper: Deformable Convolutional Networks 论文pape…

【LLM之基座】qwen 14b-4int 部署踩坑

由于卡只有24G&#xff0c;qwen14b 原生需要 30GB&#xff0c;按照官方团队的说法&#xff0c;他们用的量化方案是基于AutoGPTQ的&#xff0c;而且根据评测&#xff0c;量化之后的模型效果在几乎没有损失的情况下&#xff0c;显存降低到13GB&#xff0c;妥妥穷狗福音&#xff0…

vue使用navigator.mediaDevices.getUserMedia调用相机功能

目录 前言&#xff1a; API&#xff1a; API简单示例&#xff1a; 拍照功能 实现效果&#xff1a; 前言&#xff1a; 本文将介绍Vue中如何使用navigator.mediaDevices.getUserMedia调用相机功能&#xff0c;实现拍照使用实例&#xff0c;需要的朋友可以参考一下。 注意…

02_SHELL编程之流程控制和循环语句

课程目标 熟悉流程控制语句基本语法&#xff0c;如if…else… 掌握for循环语句的基本语法结构 掌握while和until循环语句的基本语法结构 ###一、流程控制语句 ####1. 基本语法结构 F: false 假 T: true 真 if [ condition ];thencommandcommand fi ​ [ 条件 ] &&a…

NSSCTF第12页(3)

[NSSCTF 2nd]php签到 首先&#xff0c;代码定义了一个名为 waf 的函数&#xff0c;用于执行一个简单的文件扩展名检查来防止上传恶意文件。 $black_list 是一个存储不允许的文件扩展名的数组&#xff0c;如 “ph”、“htaccess” 和 “ini”。 pathinfo($filename, PATHINF…

拥抱开源生态,算能携手软件所 PLCT 实验室联合举办 RISC-V 软件移植优化锦标赛

&#xff08;引言&#xff09;为推动RISC-V软件生态加速发展&#xff0c;算能作为RISC-V生态的领先企业&#xff0c;与RISC-V 中国社区、中科院软件所PLCT实验室联合发起“RISC-V软件移植及优化锦标赛”活动&#xff0c;以桌面和服务器软件生态为重点&#xff0c;在编译器、运行…

2023-11-17 LeetCode每日一题(最大和查询)

2023-11-17每日一题 一、题目编号 2736. 最大和查询二、题目链接 点击跳转到题目位置 三、题目描述 给你两个长度为 n 、下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;另给你一个下标从 1 开始的二维数组 queries &#xff0c;其中 queries[i] [xi, yi] 。 对于…

SOLIDWORKS参数化设计之主参数设置

SOLIDWORKS参数化设计是通过主参数来驱动整个模型的变化&#xff0c;因此确定主参数是很重要的部分。主参数可以是数值&#xff0c;也可以是条件&#xff0c;可以手动输入&#xff0c;也可以做成下拉列表。今天我们就来看看主参数的下拉列表是如何做到的。 SolidKits.AutoWork…

近期局势较多变化 适合黄金代理入场吗?

进入本年的四季度后&#xff0c;中东局势出现了比较大的变化。首先&#xff0c;巴以冲突不断的加剧&#xff0c;而且马来西亚的林吉特出现大幅贬值&#xff0c;甚至有市场论调认为&#xff0c;亚洲金融危机可能会重新点燃。从这个角度来说&#xff0c;整体的市场环境是很动荡的…

波卡三季度报告:已实现白皮书目标,异步支持与应用链技术推进

作者&#xff1a;Nicholas Garcia&#xff0c;Messari 研究分析师 编译&#xff1a;OneBlock 来源&#xff1a;https://messari.io/report/state-of-polkadot-q3-2023 知名分析平台 Messari 发布了 Polkadot 2023 年第三季度报告&#xff0c;分析了波卡的关键数据指标以及网…

【蓝桥杯选拔赛真题23】C++计算24 第十二届蓝桥杯青少年创意编程大赛C++编程选拔赛真题解析

C/C++计算24 第十二届蓝桥杯青少年创意编程大赛C++选拔赛真题 一、题目要求 1、编程实现 “计算 24”是一个流传已久的数字游戏,小蓝最近对此痴迷不已 游戏规则是:从 1~10 之间的自然数任意拿出 4 个数(4 个数各不相同,顺序随机),进行加、减、乘三种运算(使用某种运算…

0基础如何学习软件测试?10分钟给你安排明白

先上一张学习路线&#xff1a; 在测试行业已经呆了5年多了&#xff0c;也算得上行业经验资深了吧&#xff0c;基本上也是摸清了这个行业的发展。 所以今天也想对有转行想法的朋友分享一下经验&#xff0c;能够让你对这个行业有个大致的了解和对以后的发展有所规划&#xff0c;…

9.3 【MySQL】系统表空间

了解完了独立表空间的基本结构&#xff0c;系统表空间的结构也就好理解多了&#xff0c;系统表空间的结构和独立表空间基本类似&#xff0c;只不过由于整个MySQL进程只有一个系统表空间&#xff0c;在系统表空间中会额外记录一些有关整个系统信息的页面&#xff0c;所以会比独立…

Android Proguard混淆

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、人工智能等&#xff0c;希望大家多多支持。 目录 一、导读二、概览三、语法规则3.1 输入/输出选项3.2 保留选项3.3 缩…

车载终端功能盘点(车载终端工业行业解决方案案例)

​ 随着车联网的蓬勃发展,车载终端在物流运输、公共交通等领域得到广泛应用。车载终端以其强大的功能,为不同行业提供定制化的解决方案。本文将盘点车载终端的核心功能,并给出工业场景的应用案例。 一、车载终端SV900的核心功能 1. 车辆定位 车载终端集成高灵敏度的GPS模块,…

鉴源论坛 · 观模丨软件单元测试真的有必要吗?(下)

作者 | 包丹珠 上海控安产品总监 版块 | 鉴源论坛 观模 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” “软件单元测试真的有必要吗&#xff1f;&#xff08;上&#xff09;”一文中&#xff0c;着重探讨了单元测试的重要性及其正面临的困境&#xff0c…

StoneDB顺利通过中科院软件所 2023 开源之夏 结项审核

近日&#xff0c;中科院软件所-开源软件供应链点亮计划-开源之夏2023的结项名单正式出炉&#xff0c;经过三个月的项目开发和一个多月的严格审核&#xff0c;共产生 418个成功结项项目&#xff01;其中&#xff0c;StoneDB 作为本次参与开源社区&#xff0c;社区入选的两个项目…

<shell>《Shell脚本-极简实用手册(高级)》 (自用、持续更新)

1 变量 1.1 2>&1 解释&#xff1a;将“标准错误”输出到“标准输出文件中”。 示例&#xff1a;cat /etc/hosts >> $LOG 2>&1 说明&#xff1a; 1、使用 > 或 >> 时&#xff0c;默认为标准输出 1 重定向, 所以 > file 就是 1> file 的省…