【C++】了解模板

这里是目录

  • 前言
  • 函数模板
  • 函数模板的实例化
  • 类模板

前言

如果我们要交换两个数字,那么我们就需要写一个Swap函数来进行交换,那如果我们要交换char类型的数据呢?那又要写一份Swap的函数重载,参数的两个类型是char,那我们还要交换double类型的数据呢?难道又要写一份Swap函数重载?如果在添加个自定义类型的交换呢?
模板的作用就是解决此类问题,模板的主要功能是实现通用

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

函数模板

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

基本用法:

template<typename T>
//这里的typename也可以换为class,一般情况下用typename居多
//也可以多参数
template<class T1, class T2>

实现一个交换函数模板:

template<typename T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}

template<typename T> //模板参数 一般命名为T TY TP
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a = 2, b = 1;double c = 2.2, d = 1.1;cout << "交换前->" << a << " " << b << endl;Swap(a, b);cout << "交换后->" << a << " " << b << endl;cout << "交换前->" << c << " " << d << endl;Swap(c, d);cout << "交换后->" << c << " " << d << endl;return 0;
}

运行效果:
在这里插入图片描述
可以看到已经完成了交换,但实际上他们调用的并不是同一个函数,在编译器上看他们确实是调用的同一个函数,但是如果查看汇编就能发现他们调用的是不同的函数

在这里插入图片描述

可以看到调用的函数地址不相同

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此

模板的实例化图解:
在这里插入图片描述
C++库中是有交换函数的,只不过库里的是小写,所以我们以后想要交换数据直接用库里的就好了
在这里插入图片描述
函数模板可以有多个参数

template<typename T1,typename T2>
void Func(const T1& x, const T2& y)
{cout << x << " " << y << endl;
}

函数模板可以做返回值

template<typename T1,typename T2>
T1 Func(const T1& x, const T2& y)
{cout << x << " " << y << endl;return x;
}

函数模板实例化生成具体函数
函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数

函数模板的实例化

模板的实例化有两种方式
一种是隐式实例化:让编译器根据实参推演模板参数的实际类型
还有一种是显式实例化:在函数名后的<>中指定模板参数的实际类型

template<typename T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a = 10;int b = 20;double c = 10.0;double d = 20.0;//编译器自动推导cout << Add(a, b) << endl;cout << Add(c, d) << endl;//但是下面这种场景如果让编译器自动推导就会出问题cout << Add(a, d) << endl;return 0;
}

左边的T是int右边的T是double,那到底是T推导成int还是double呢?
这时候编译器就会出现问题了

错误信息:
在这里插入图片描述
有两种方法可以解决这个问题
方法一:

cout << Add(a, (int)d) << endl;
cout << Add((double)a, d) << endl;

这样就不会出现推导歧义了

方法二:

//显式实例化,用指定类型实例化
cout << Add<int>(a, d) << endl;
cout << Add<double>(a, d) << endl;

大部分模板都不需要显式实例化,只有少数需要
比如:

template<typename T>
T* Alloc(int n)
{return new T[n];
}int main()
{//有些函数无法自动推导,只能显式实例化double* arr = Alloc<double>(10);return 0;
}

类模板

//类模板
template<typename T>
class Stack
{
public:Stack(size_t capacity = 3){_array = new T[capacity];_capacity = capacity;_size = 0;}private:T* _array;int _capacity;int _size;
};int main()
{Stack<int> s1;Stack<double> s2;Stack<char> s3;return 0;
}

有了类模板就可以实现一个栈存储多类型的需求

类模板的声明和定义分离和普通的类不同:

//类模板
template<typename T>
class Stack
{
public:Stack(size_t capacity = 3);private:T* _array;int _capacity;int _size;
};//普通类,类名和类型是一样的
//类模板,类名和类型不一样,
//类名是:Stack
//类型是:Stack<T>
//最好不要分离到两个文件
template<typename T>
Stack<T>::Stack(size_t capacity)
{_array = new T[capacity];_capacity = capacity;_size = 0;
}int main()
{//类模板实例化Stack<int> s1;Stack<double> s2;Stack<char> s3;return 0;
}

总结:

优点:

  1. 灵活性, 可重用性和可扩展性
  2. 可以大大减少开发时间,模板可以把用同一个算法去适用于不同类型数据,在编译时确定具体的数据类型
  3. 模版模拟多态要比C++类继承实现多态效率要高,无虚函数,无继承

缺点:

  1. 可读性不好,调试比较困难
  2. 模板的数据类型只能在编译时才能被确定
  3. 所有用基于模板算法的实现必须包含在整个设计的.h头文件中, 当工程比较大的时候, 编译时间较长

以上就是本篇文章的全部内容了,希望大家看完能有所收获

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

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

相关文章

phpoffice在tp框架中如何实现导入导出功能

安装 phpoffice/phpspreadsheet 库 composer require phpoffice/phpspreadsheet 导入功能 创建一个用于上传文件的视图&#xff0c;可以使用元素来实现文件上传。 <!-- application/view/your/import.html --><form action"{:url(your/import)}" method&q…

2021年8月18日 Go生态洞察:整合Go的网络体验

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

WIN10系统自带硬盘测速工具使用

前段时间在捣腾电脑硬盘这一块&#xff0c;因为现在固态硬盘价格比较低了&#xff0c;所以想换一下&#xff0c;给自己的电脑升个级。现在硬盘有多种接口&#xff0c;常见的就是SATA&#xff0c;mSATA&#xff0c;m.2, NVME&#xff0c;PCIE。这里PCIE的接口是直连的&#xff0…

C语言--每日选择题--Day31

第一题 1. 下面程序 i 的值为&#xff08;&#xff09; int main() {int i 10;int j 0;if (j 0)i; elsei--; return 0; } A&#xff1a;11 B&#xff1a;9 答案及解析 B if语句中的条件判断为赋值语句的时候&#xff0c;因为赋值语句的返回值是右操作数&#xff1b; …

机器学习模型验证——以数据为中心的方法

构建机器学习模型时&#xff0c;人们往往将激情和精力集中于收集数据和训练模型&#xff0c;对测试模型和验证结果往往缺少应有的关注。正确的验证技术有助于估计无偏见的广义模型的性能&#xff0c;并更好地理解模型训练的效果。您需要确保机器学习模型经过准确的训练&#xf…

EUREKA: HUMAN-LEVEL REWARD DESIGN VIACODING LARGE LANGUAGE MODELS

目录 一、论文速读 1.1 摘要 1.2 论文概要总结 相关工作 主要贡献 论文主要方法 实验数据 未来研究方向 二、论文精度 2.1 论文试图解决什么问题&#xff1f; 2.2 论文中提到的解决方案之关键是什么&#xff1f; 2.3 用于定量评估的数据集是什么&#xff1f;代码有…

2023.11.28 使用tensorflow进行“三好“权重分析

2023.11.28 使用tensorflow进行"三好"权重分析 这是最基础的一个神经网络问题。许久没有再使用&#xff0c;用来做恢复训练比较好。 x1w1 x2w2 x3*w3 y&#xff0c;已知x1,x2,x3和y&#xff0c;求w1,w2,w3 这是一个三元一次方程&#xff0c;正常需要三组数据就能…

软件工程--需求工程--学习笔记(超详细)

软件需求工程是软件开发周期的第一个阶段&#xff0c;也是关系到软件开发成败最关键阶段&#xff0c;本章讲解需求的基础知识和需求工程的关键活动。这些知识对于结构化方法、面向对象方法、面向服务方法等都是适用的 本文参考教材&#xff1a;沈备军老师的《软件工程原理》 目…

js提取iconfont项目的图标

iconfont 可以让我们轻松使用字体图标&#xff0c;比如使用 iconfont 提供的 js&#xff0c;就可以愉快的码代码了。 //at.alicdn.com/t/c/font_xxxxx.js通常公司会有提供一套图标供所有系统使用&#xff0c;比如图标库里有 1000 个图标&#xff0c;但某个项目只需要使用 10 个…

系列十九、Spring实例化bean的方式

一、概述 所谓实例化bean&#xff0c;大白话讲就是Spring如何把这一个个的普通的Java对象创建为Spring bean的。 二、方式 Spring中实例化bean常用的有以下四种&#xff0c;即&#xff1a; ① 构造器方式&#xff1b; ② 静态工厂方式&#xff1b; ③ 实例工厂方式&#xff1b;…

关于mybatis插入返回主键id和SpringBoot事务注解自调用演示

文章目录 一. 插入返回任意规则主键ID二. SpringBoot自调用事务2.1 场景12.2 场景2 自调用结论总结 一. 插入返回任意规则主键ID 实体对象 TableName("bank") Data public class Entity {TableId("id")Integer id;TableField("money")Integer …

超详细!Opencv人脸识别!附源码!

一、新建环境 注意&#xff01;&#xff01;确定后需要关闭项目&#xff0c;重新打开&#xff0c;终端的环境才会变化&#xff01;&#xff01; 二、下载安装包&#xff08;只需要3个即可&#xff09; 1. 下载dlib包 pip install dlib-19.19.0-cp38-cp38-win_amd64.whl.whl …

Linux 如何在文件中查找指定内容,grep的用法

Linux 如何在文件中查找指定内容 1、 如我们 查找 log_file_catalina.out 文件中&#xff0c;包含 ‘总数&#xff1a;900’ 的字符内容 2、 在日志中查看 83910_law_21CFBC7EB25B1FF60255FE7F4BE1BCCF1CE726F6_0.bdyhf 的相关内容 grep 83910_law_21CFBC7EB25B1FF60255FE7…

人工智能概论

一、关键技术 人工智能包含了七项关键技术: 1. 机器学习: 机器学习是研究计算机怎样模拟或实现人类的学习行为&#xff0c;以获取新的知识或技能&#xff0c;重新组织已有的知识结构使之不断改善自身的性能&#xff0c;是人工智能技术的核心。 从学习模式划分&#xff0c;分…

虚拟数据生成_以Python为工具

生成虚拟数据_以Python为工具 生成虚拟数据技术在现实生活中具有多个重要的应用领域。它为数据隐私保护、机器学习算法开发、数据处理和可视化等方面提供了实用且有价值的解决方案。尤其是能满足定制化需求的虚拟数据&#xff0c;在预期的方向上让数据定向随机。 &#x1f339…

原生GPT本地及云端部署方式保姆级教程

前提条件 部署必须要有一个超过1年的Github账号 本地服务部署 运行效果 部署方法 下载安装包 暂时无法在飞书文档外展示此内容 GitHub授权登录&#xff1a; https://dash.pandoranext.com/ 登录后是这个样子&#xff1a; 复制下面红框里面这个License Id 编辑Config.js…

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级 在之前的开发过程中&#xff0c;需要实现卡片轮播效果&#xff0c;但是卡片轮播需要中间大、两边小一些的效果&#xff0c;这里就使用到了Swiper。具体效果如视频所示 添加链接描述 这里需要的效果是中间大、两边…

【人工智能Ⅰ】实验3:蚁群算法

实验3 蚁群算法的应用 一、实验内容 TSP 问题的蚁群算法实现。 二、实验目的 1. 熟悉和掌握蚁群算法的基本概念和思想&#xff1b; 2. 理解和掌握蚁群算法的参数选取&#xff0c;解决实际应用问题。 三、实验原理 1&#xff0e;算法来源 蚁群算法的基本原理来源于自然界…

【JavaScript】3.2 JavaScript性能优化

文章目录 1. 避免全局查找2. 避免不必要的属性查找3. 使用快速的JavaScript方法4. 避免不必要的DOM操作5. 使用Web Workers进行后台处理总结 性能优化是任何编程语言的重要组成部分&#xff0c;JavaScript也不例外。在这个章节中&#xff0c;我们将探讨如何优化JavaScript代码&…

GAN:WGAN

论文&#xff1a;https://arxiv.org/pdf/1701.07875.pdf 发表&#xff1a;2017 WGAN 算法流程 从GAN 到 WGAN 的转变 相比于原始 GAN&#xff0c;WGAN 只需要修改以下几点&#xff0c;就能使得训练更稳定&#xff0c;生成质量更高&#xff1a; 1. 此时的判别器相当于做回归…