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

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. 模板的本质

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

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

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

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES7升级、jar包升级、工具类封装,代码改造

一、spring-data-elasticsearch 引入es版本适配 二、jar升级 在项目工程根pom.xml文件中增加maven依赖管理在这里插入图片描述<properties><elasticsearch.spring.version>4.2.0</elasticsearch.spring.version>

Genio 500_MT8385安卓核心板:功能强大且高效

Genio 500(MT8385)安卓核心板是一款功能强大且高效的AIoT平台&#xff0c;内置的AI处理器(APU)工作频率可达500MHz&#xff0c;支持深度学习、神经网络加速和计算机视觉应用。配合高达2500万像素的摄像头&#xff0c;可以为AI相机应用提供清晰、精确的图像&#xff0c;如人脸识…

怎么防止U盘复制电脑文件

随着信息化的快速发展&#xff0c;数据安全问题越来越受到人们的关注。U盘作为一种常用的数据传输工具&#xff0c;有时会被用于非法复制电脑文件&#xff0c;从而给企业或个人带来损失。因此&#xff0c;防止U盘复制电脑文件成为保护数据安全的重要措施之一。 一、我们应该提高…

为什么原生IP可以降低Google play账号关联风险?企业号解决8.3/10.3账号关联问题?

在Google paly应用上架的过程中&#xff0c;相信大多数开发者都遇到过开发者账号因为关联问题&#xff0c;导致应用包被拒审和封号的情况。 而众所周知&#xff0c;开发者账号注册或登录的IP地址及设备是造成账号关联的重要因素之一。酷鸟云最新上线的原生IP能有效降低账号因I…

TensorRT基础知识及应用【学习笔记(十)】

这篇博客为修改过后的转载&#xff0c;因为没有转载链接&#xff0c;所以选了原创 文章目录 一、准备知识1.1 环境配置A. CUDA DriverB. CUDAC. cuDNND. TensorRT 1.2 编程模型 二、构建阶段2.1 创建网络定义2.2 配置参数2.3 生成Engine2.4 保存为模型文件2.5 释放资源 三、运…

一键整合,万用万灵,Python3.10项目嵌入式一键整合包的制作(Embed)

我们知道Python是一门解释型语言&#xff0c;项目运行时需要依赖Python解释器&#xff0c;并且有时候需要安装项目中对应的三方依赖库。对于专业的Python开发者来说&#xff0c;可以直接通过pip命令进行安装即可。但是如果是分发给其他的Windows用户&#xff0c;特别是不熟悉Py…

【网络奇幻之旅】那年我与互联网的邂逅

&#x1f33a;个人主页&#xff1a;Dawn黎明开始 &#x1f380;系列专栏&#xff1a;网络奇幻之旅 ⭐每日一句&#xff1a;不想留在过去&#xff0c;就要变得更好 &#x1f4e2;欢迎大家&#xff1a;关注&#x1f50d;点赞&#x1f44d;评论&#x1f4dd;收藏⭐️ 文章目录 &a…

SaaS与PaaS平台的区别

目录 一、前言 二、SaaS化与PaaS化平台的区别 三、PaaS化的低代码平台更胜一筹 PaaS优势&#xff1a; 支持PaaS服务的低代码平台 1.私有化部署&#xff0c;为数据安全保驾护航 2.业内领先技术&#xff0c;为开发强势赋能 3.超强集成能力&#xff0c;系统对接无忧 4.源代码交付&…

企业微信获取第三方应用凭证

上一篇介绍了如何配置通用开发参数及通过url回调验证&#xff0c; 本篇将通过服务商后台配置关联小程序应用配置和获取第三方凭证及如何配置企业可信IP。 当然上篇配置的回调设置也不会白费&#xff0c;在下方的指令和数据回调会用到。 第三方应用开发流程 官方企业微信第三方…

v-for 循环数组的某一部分

方法一&#xff1a;使用slice()方法 代码&#xff1a; <template><div><!--循环前三个元素--><span v-for"(item, index) in arr.slice(0, 3)" :key"index a">{{ item }}</span> <br><!--循环前第六个到第九个元…

语义检索系统【全】:基于milvus语义检索系统指令全流程-快速部署版

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

【Android】带下划线的TextView

序言 我们有时候需要一个类似这样的显示&#xff0c;上面是文字&#xff0c;下面是一条线 这样的显示效果是TextView实现不了的&#xff0c;需要我们自己进行修改一下。 实现 创建一个UnderlineTextView&#xff0c;继承系统的TextView class UnderlineTextView(mContext…

LeetCode(23)找出字符串中第一个匹配项的下标【数组/字符串】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 找出字符串中第一个匹配项的下标 1.题目 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 hays…

如何选择适合企业的ERP管理系统

如何选择适合企业的ERP管理系统&#xff1f; 企业业务不断发展和扩大&#xff0c;ERP管理系统已成为企业实现信息化管理、提高工作效率、降低成本的重要工具。然而&#xff0c;市场上ERP管理系统种类繁多&#xff0c;如何选择适合自己企业的ERP管理系统成为了企业面临的难题。本…

大力说企微第一课:企业微信的注册验证和认证

这段时间有好几个朋友问我&#xff0c;怎么用企业微信&#xff0c;还有一些朋友反馈&#xff0c;企业微信使用起来不太方便。 在我的印象中&#xff0c;企业微信确实不如微信那么简单&#xff0c;毕竟用户对象是企业&#xff0c;是企业就有多个部门&#xff0c;就有流程&#x…

自律成就未来:中国人民大学与加拿大女王大学金融硕士项目引领金融精英之路

在这个日新月异的时代&#xff0c;金融行业正以前所未有的速度发展&#xff0c;对金融人才的需求也日益增长。为了培养更多具备专业素养、创新精神和国际视野的金融精英&#xff0c;中国人民大学与加拿大女王大学金融硕士项目应运而生&#xff0c;致力于为学员提供一个全面提升…

如何构建风险矩阵?3大注意事项

风险矩阵法&#xff08;RMA&#xff09;是确定威胁优先级别的最有效工具之一&#xff0c;可以帮助项目团队识别和评估项目中的风险&#xff0c;帮助项目团队对风险进行排序&#xff0c;清晰地展示风险的可能性和严重性&#xff0c;为项目团队制定风险管理策略提供依据。 如果没…

车联网解决方案(车联网设备安装部署案例)

车联网&#xff08;Connected Car&#xff09;是指通过无线通信技术将汽车与互联网连接起来&#xff0c;实现车辆与车辆之间、车辆与道路基础设施之间以及车辆与互联网之间的信息交流和实时控制。车载网关是车联网系统中的核心设备之一&#xff0c;负责将车辆内部的数据传输到云…

[msg_msg] corCTF2021 -- fire_of_salvation

前言 msg_msg 是 kernel pwn 中经常用作堆喷的结构体. 其包含一个 0x30 大小的 header. 但 msg_msg 的威力远不如此, 利用 msg_msg 配合其他堆漏洞可以实现任意地址读写的功能. 程序分析 本题给了源码, 可以直接对着源码看. 并且题目给了编译配置文件, 所以可以直接编译一个…

vue部署之后提示用户更新的两种方式(http请求和worker线程请求)

const { writeFile, mkdir, existsSync } require(fs) // 动态生成版本号 const createVersion () > {// mkdir(./dist, { recursive: true }, (err) > {//检测dist目录是否存在if (existsSync(./dist)) {writeFile(./dist/version.json, {"version":"$…