【C++干货铺】初识模板

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

泛型编程

函数模板

函数模板格式

函数模板原理

函数模板实例化

模板参数的匹配原则

类模板

定义格式

类模板的实例化


泛型编程

什么是泛型?

  • 在计算机程序设计领域,为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,人们发展的泛型及泛型编程技术。

就好比今天老师布置了一篇800的作文,文体不限,我们可以写散文、诗歌、叙事文等等各种文章类型,但是最终只要800的作文。

泛型编程概念:

泛型编程允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型在实例化时作为参数指明这些类型

我们知道C++语言支持函数重载,一个函数名可以写好多种参数类型不同的交换函数。像下面这样:

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;
}
void swap(char& x, char& y)
{char tmp = x;x = y;y = tmp;
}
int main()
{int a = 1, b = 2;swap(a, b);double x = 1.1, y = 2.2;swap(x, y);char s = a, z = b;swap(s, z);return 0;
}

上面的代码只是简单的 三个相同类型的交换,使用函数重载虽然可以实现但是有几点不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
2. 代码的可维护性比较低,一个出错可能所有的重载均出错

如果我们想实现两两不同类型的相加呢?如何实现一个通用的加法函数呢?那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

 

ps:图片来源网络

向上面的各种各样的汉堡一样,上下都是两片面包只是中间加入的东西不一样,夹鸡腿就叫鸡腿堡、夹猪排就叫猪排堡、夹牛肉就叫牛肉堡等等。

如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。

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


函数模板

函数模板概念

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

函数模板格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表)
{}

template是一个关键字

我们按照上面的格式编写一个交换函数模板

template <typename T>
void swap(T& left, T& right)
{T tmp = left;left = right;right = tmp;
}

 注意:

typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

函数模板原理

那么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。有人给出了论调:懒人创造世界。

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

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

函数模板实例化

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

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

template<class T>
void Swap(T& left, T& right)
{T tmp = left;left = right;right = tmp;
}
int main()
{int i = 1, j = 0;Swap(i,j);double x = 1.1, y = 2.2;Swap(x, y);char s = 'a', z = 'b';Swap(s, z);return 0;
}

如果我们要进行两两不同类型的两个数相加呢?

用户自己来强制转化

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a = 1;double b = 1.1;Add(a, (int)b);//自己手动进行类型转化return 0;
}

显示实例化:在函数名后的<>中指定模板参数的实际类型(解决参数类型不匹配类型)

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a = 1;double b = 1.1;Add(a, (int)b);//手动强制类型转化Add<double>(a, b);//显示实例化return 0;
}

模板参数的匹配原则

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

// 专门处理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版本
}

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

// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}

3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换


类模板

定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public:Vector(size_t capacity = 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}// 使用析构函数演示:在类中声明,在类外定义。~Vector();void PushBack(const T& data);void PopBack();// ...size_t Size() { return _size; }T& operator[](size_t pos){assert(pos < _size);return _pData[pos];}
private:T* _pData;size_t _size;size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{if (_pData)delete[] _pData;_size = _capacity = 0;
}

上面的类模板可以根据不同的数据类型,生成不同的类(顺序表)

类模板的实例化

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

// Vector类名,Vector<int>才是类型
Vector<int> s1;
Vector<double> s2;

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,您的支持就是我前进的动力!  

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

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

相关文章

麒麟v10 安装jenkins

1.想安装哪个版本&#xff1f; https://pkg.jenkins.io/redhat-stable/ 我们查看我们想要哪个版本&#xff1a; 4年前安装的是 Jenkins2.279 版本 现在在docker 上安装的是Version 2.425 版本 2.碰到到的问题 1.安装老版本的Jenkins&#xff0c;会出现安装的插件不兼容&…

【前段基础入门之】=>CSS3新特性 文本多列 布局

概述&#xff1a; 作用&#xff1a;专门用于实现类似于报纸的布局。属于是一行文本多列布局 属性/值描述column-count 指定列数&#xff0c;值是数字。column-width指定列宽&#xff0c;值是长度单位columns同时指定列宽和列数&#xff0c;复合属性&#xff1b;值没有数量和顺序…

Python基础教程之七:Python字符串操作

在Python中&#xff0c;string文字是&#xff1a; 代表Unicode字符的字节数组用单引号或双引号引起来无限长度 字符串文字 str hello worldstr "hello world"一个多行字符串使用三个单引号或三个双引号创建的。 多行字符串文字 str Say helloto pythonprogra…

Spring Cloud - 通过 Gateway webflux 编程实现网关异常处理

一、webflux 编程实现网关异常处理 我们知道在某一个服务中出现异常&#xff0c;可以通过 ControllerAdvice ExceptionHandler 来统一异常处理&#xff0c;即使是在微服务架构中&#xff0c;我们也可以将上述统一异常处理放入到公共的微服务中&#xff0c;这样哪一个微服务需要…

LangChain之关于RetrievalQA input_variables 的定义与使用

最近在使用LangChain来做一个LLMs和KBs结合的小Demo玩玩&#xff0c;也就是RAG&#xff08;Retrieval Augmented Generation&#xff09;。 这部分的内容其实在LangChain的官网已经给出了流程图。 我这里就直接偷懒了&#xff0c;准备对Webui的项目进行复刻练习&#xff0c;那么…

多语言多商户多货币跨境电商商城源码(一键铺货\订单返现商城源码搭建开发)

随着全球化的加速和互联网的蓬勃发展&#xff0c;跨境电商已成为越来越多企业的必经之路。如何在竞争激烈的市场中脱颖而出&#xff0c;实现多语言、多商户的跨境商城运营&#xff0c;成为了很多电商企业亟待解决的问题。今天&#xff0c;我们将为您揭示一款多语言多商户跨境商…

2023年11月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2023年11月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

开源DB-GPT实现连接数据库详细步骤

官方文档&#xff1a;欢迎来到DB-GPT中文文档 — DB-GPT &#x1f44f;&#x1f44f; 0.4.1 第一步&#xff1a;安装Minicoda https://docs.conda.io/en/latest/miniconda.html 第二步&#xff1a;安装Git Git - Downloading Package 第三步&#xff1a;安装embedding 模型到…

seata事务回滚引起的skywalking数据库存储空间剧增的问题排查

基本信息 产品名称&#xff1a;ATS3.0 问题分类&#xff1a;编码问题 环境类型&#xff1a;环境无关 问题现象 11月1日上午华润DBA收到数据库磁盘空间告警&#xff0c;检查后发现skywalking连接的mysql数据库占用空间从之前一直是比较稳定的&#xff0c;但是10月31日…

antd Form 校验自定义复杂判断-validator

antd Form 校验 加入自定义复杂逻辑 <Form.Itemlabel"编码"name"code"rules{[{required: true,validator: (_rule, value) > {if (value ) {return Promise.reject(请输入编码);}return IsExist(value).then((res) > {if (res?.statusCode 20…

强化学习中广义策略迭代

一、广义策略迭代 策略迭代包括两个同时进行的交互过程&#xff0c;一个使价值函数与当前策略保持一致&#xff08;策略评估&#xff09;&#xff0c;另一个使策略在当前价值函数下变得贪婪&#xff08;策略改进&#xff09;。在策略迭代中&#xff0c;这两个过程交替进行&…

【Qt之QAssociativeIterable】使用

介绍 QAssociativeIterable类是QVariant中一个关联式容器的可迭代接口。这个类允许多种访问在QVariant中保存的关联式容器元素的方法。如果一个QVariant可以转换为QVariantHash或QVariantMap&#xff0c;那么QAssociativeIterable的实例可以从中提取出来。 QHash<int, QSt…

软件版本控制系统VCS工具——cvs vss svn git

版本控制 版本控制系统&#xff08;Version Control System&#xff0c;VCS&#xff09;是用于跟踪和管理源代码和文档的工具。可追踪和管理修改历史&#xff0c;包括修改的内容、时间、作者等信息。有助于团队协作、追踪变更、恢复历史版本等。VCS的主要目的是帮助团队协作开…

电脑如何截屏?一起来揭晓答案!

在数字时代&#xff0c;截屏已经成为我们日常生活和工作中的必备技能。无论是为了捕捉有趣的网络瞬间&#xff0c;保存重要信息&#xff0c;还是为了协作和教育&#xff0c;电脑截屏都是一个强大而方便的工具。本文将介绍三种电脑如何截屏的方法&#xff0c;以满足各种需求&…

研发管理工具选型要考虑哪些内容?

研发管理工具选型要考虑哪些内容&#xff1f; 研发管理工具选型需要考虑六个因素&#xff0c;分别是&#xff1a;1、功能性&#xff1b;2、非功能性&#xff1b;3、易用性&#xff1b;4、产品价格&#xff1b;5、服务&#xff1b;6、厂商。其中功能性在研发管理工具选型过程中是…

精美好看又便于分享的电子相册制作,谁看了不心动呢?

很多人都喜欢用相机记录生活中的点点滴滴&#xff0c;可是当要分享到朋友圈的时候&#xff0c;觉得这张也好看&#xff0c;那张也不错&#xff0c;如果全部分享出去就霸屏了&#xff0c;然后就不知道怎么选择了。其实&#xff0c;我们可以把这些照片做成电子相册&#xff0c;然…

docker可视化

什么是portainer&#xff1f; portainer就是docker图形化界面的管理工具&#xff0c;提供一个后台面板供我们操作 目前先用portainer(先用这个)&#xff0c;以后还会用到Rancher(CI/CD在用) 1.下载portainer 9000是内网端口&#xff0c;8088是外网访问端口 docker run…

对话凯文·凯利:AI 会取代人的 90% 技能,并放大剩余的 10%

采访 | 邹欣&#xff0c;CSDN 副总裁 作者 | 王启隆 责编 | 唐小引 出品 | 《新程序员》编辑部 5000 天后&#xff0c;你都会做些什么&#xff1f; 是和 AI 助手一起编程&#xff0c;还是让生活完全由 AI 掌控&#xff0c;自己坐享其成&#xff1f;如果到时候还要上班&a…

采购劳保鞋如何选择合适的尺码

今天在某问答平台看到了这么一个话题&#xff0c;平常皮鞋穿40码&#xff0c;运动鞋穿41码&#xff0c;劳保鞋如何选择合适的尺码&#xff1f;小编发现很多朋友在选购劳保鞋的时候&#xff0c;对劳保鞋的尺码了解不是很清楚都会在这一块纠结。选择鞋子脚感舒适很重要&#xff0…

射频功率放大器应用中GaN HEMT的表面电势模型

标题&#xff1a;A surface-potential based model for GaN HEMTs in RF power amplifier applications 来源&#xff1a;IEEE IEDM 2010 本文中的任何第一人称都为论文的直译 摘要&#xff1a;我们提出了第一个基于表面电位的射频GaN HEMTs紧凑模型&#xff0c;并将我们的工…