当前位置: 首页 > news >正文

c++模板的简单认识

 

 

文章目录

  • 前言
  • 一.泛型编程
  •      函数模板
  •      模板参数的匹配原则
  •      类模板
  • 总结

 


前言

ADD函数很好写,但是如果我们要有int类型的,double类型的,char类型的等等各种类型,难道要写这么多不同的ADD函数吗,这么写简直太麻烦了,所以有了泛型编程的概念。


 

一、泛型编程

实现一个通用的ADD函数有很多办法,就比如函数重载,但是函数重载又有很多的缺点,比如:

1.重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数。

2.代码的可维护性比较低,一个出错可能所有的重载都出错。

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生产代码呢?

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

函数模板

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

函数模板格式:

template<typename p1,typename p2........>

注意:typename用来定义模板参数关键字也可以使用class(切记:不能使用struct代替class)
template <class T>
void Swap(T& d1, T& d2)
{T tmp = d1;d1 = d2;d2 = tmp;
}
int main()
{int a = 10, b = 50;Swap(a, b);double c = 2.36, d = 6.15;Swap(c, d);return 0;
}

3b40aac6911a4438bf22fb7ba793e11c.png

那么上图中的两次调用Swap函数是同一个函数吗?这里不是同一个函数,我们先来验证一下:

2a078b1112d14e37b9b44383c42af471.png f3a3c429bf594036a65ca23a55f30a33.png

 通过汇编代码我们发现两个函数并不是同一个,他们有着不同的地址。这是因为模板就像是印刷的模具一样,生成的函数就是印刷出来的书,我们看的是书并不是印刷的板,每本书用的印刷的板都是一样的但是书中的内容是不一样的。

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

 e10acf4bb36241c9b20e04ae82d91700.png

 下面我们来看一些关于模板的小细节:

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double d1 = 10.22, d2 = 20.32;cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;return 0;
}

首先上面的代码是可以正常编译的,那么如果写成下面这样呢?

6e2c58f90b304e4fa0c50c06917a0a23.png

这里有两种解决方式,一种是强制类型转换,一种是显式实例化。

int main()
{int a1 = 10, a2 = 20;double d1 = 10.22, d2 = 20.32;//实参传递给形参,自动推演模板类型cout << Add(a1, (int)d1) << endl;cout << Add(d1, d2) << endl;//显示实例化cout << Add<int>(a1, d2) << endl;cout << Add<double>(a1, d1) << endl;return 0;
}

ebf3f3fbd892496faaa16a9d6b77c830.png

 在函数名后加<(需要的类型)>就可以完成显式实例化,编译器直接以显式的类型去计算。

模板参数的匹配原则

// 专门处理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版本
}
int main()
{Test();return 0;
}

87d7c08fce4b43aeb6f5d2d9b3e91c6a.png

 我们可以看到上面代码中有两个Add函数,当他们类型都为int的时候为什么没有函数重定义呢?

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

586ed4cd9714418d81e70ccdb1c85a89.png

那么像上图这样的情况编译器会调用哪个呢?答案是第一个,因为对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的一个函数,那么将选择模板。

什么意思呢?就是说已经存在一个能用的函数了编译器就不会花时间去实例化一个相同的函数,而是调用那个已经存在的函数。

如果我们必须要调用那个模板有什么方法吗?

caced6abeec24b7f9107748a648f8010.png 我们直接在函数名后显示实例化就会调用模板了。

类模板 

template<class T>
class Stack
{
public:Stack(int capacity = 4){_a = new T[capacity];_top = 0;_capacity = capacity;}~Stack(){delete[] _a;_a = nullptr;_top = _capacity = 0;}
paivate:T* _a;size_t _top;size_t _capacity;
};
int main()
{Stack<int> sl;Stack<double> st;return 0;
}

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

注意:模板的声明和定义分开与普通类不一样,如下图:

b832acdbfdc040a6bff91e7d6e533c99.png

9cb58e09c3074b2d85fc4be48a85c823.png 模板的声明和定义分离只限于在一个文件中,如果声明和定义在两个不同的文件会出现链接错误。

0472bfbf0be34f47922594518edffe59.png

模板的类创建对象必须显示实例化在类名后面加<>确定其类型。 

 


总结

模板的出现让我们在写一些代码相同但是类型不同的函数或者类的时候方便了很多,以前这些都是由我们自己写出来的,有了模板就可以由编译器去做这件事,并且编译器做的比我们更好,因为人写总是会出现一些粗心的错误,编译器却不会。

 

相关文章:

c++模板的简单认识

文章目录 前言一.泛型编程 函数模板 模板参数的匹配原则 类模板总结前言 ADD函数很好写&#xff0c;但是如果我们要有int类型的&#xff0c;double类型的&#xff0c;char类型的等等各种类型&#xff0c;难道要写这么多不同的ADD函数吗&#xff0c;这么写简直太麻…...

真香!Linux 原来是这么管理内存的

Linux 内存管理模型非常直接明了&#xff0c;因为 Linux 的这种机制使其具有可移植性并且能够在内存管理单元相差不大的机器下实现 Linux&#xff0c;下面我们就来认识一下 Linux 内存管理是如何实现的。 一&#xff0c;基本概念 每个 Linux 进程都会有地址空间&#xff0c;这…...

计网之IP协议和以太网

文章目录一. IP协议1. IPv4报头介绍2. 解决IPv4地址不够用的问题3. IP地址管理4. 路由选择二. 以太网三. 浅谈DNS域名解析系统一. IP协议 IP协议是位于OSI模型中第三层(网络层)的协议, 在这层上工作的不止这一个协议, 但IP协议是网络层传输所使用的最主流的一种协议, 有IPv4和…...

华为OD机试 - 关联子串(Python) | 机试题+算法思路+考点+代码解析 【2023】

关联子串 题目 给定两个字符串str1和str2 如果字符串str1中的字符,经过排列组合后的字符串中 只要有一个是str2的子串 则认为str1是str2的关联子串 若不是关联子串则返回-1 示例一: 输入: str1="abc",str2="efghicaibii" 输出: -1 预制条件: 输入的…...

SpringBoot学习笔记(二)

配置文件分类 SpringBoot中4级配置文件 1级&#xff1a;file&#xff1a;config/application.yaml 【最高】 2级&#xff1a;file&#xff1a;application.yml 3级&#xff1a;classpath&#xff1a;config/application.yml 4级&#xff1a;classpath&#xff1a;application.…...

亚马逊云科技SageMaker:实现自动、可视化管理迭代

现如今&#xff0c;AI正在成为跨时代的技术&#xff0c;在数字经济发展中登上舞台&#xff0c;发挥关键作用。在Gartner发布的《2022年新兴技术成熟度曲线》*报告中&#xff0c;AIGC&#xff08;即AI Generated Content&#xff0c;人工智能自动生成内容&#xff09;被列为2022…...

汽车 Automotive > CAN Transceivers收发器选择

参考&#xff1a;https://www.nxp.com/products/interfaces/can-transceivers/3-3-v-5-v-io-can-transceivers:33VIO-CAN3.3 V / 5V IO CAN收发器组合TJA1042高速CAN收发器&#xff0c;具有待机模式&#xff0c;适用于所有类型的高速CAN网络&#xff0c;在需要低功耗模式的节点…...

AI将如何影响程序员的未来,以及如何不被AI所替代。

随着人工智能技术的不断发展&#xff0c;越来越多的工作被自动化和智能化所取代&#xff0c;其中程序员这个职业也不例外。然而&#xff0c;我们需要客观地分析AI在未来对程序员的影响&#xff0c;并且给出建议&#xff0c;以便程序员能够保持竞争力&#xff0c;不被AI所取代。…...

nginx 常用配置之 pass_proxy

大家好&#xff0c;我是 17。 今天和大家聊聊 pass_proxy 代理。 pass_proxy 代理 在前端代理主要是为了跨域。虽然前端跨域有多种方法&#xff0c;各有利弊&#xff0c;但用代理来跨域对开发是最友好的。用代理可以不用修改产品代码切换线上线下&#xff0c;非常安全。pass…...

Linux中驱动模块加载方法分析

如何管理驱动模块 由于Linux驱动模块众多&#xff0c;系统对模块加载顺序有要求&#xff0c;一些基础模块在系统启动时需要很早就被加载&#xff1b;开发者加入自己的模块时&#xff0c;需要维护一个模块初始化列表&#xff0c;上面两方面的做起来很困难&#xff0c;为了科学地…...

yarn 通过 resolutions,指定子孙依赖包版本号,解决froala-editor 版本问题

前端开发项目过程中会使用到各种依赖包。但是这些依赖包虽然好用&#xff0c;但是一味使用最新版本可能会出现各种奇葩问题&#xff0c;因此我们经常会针对一些依赖包指定一个稳定版本。 常用版本 版本号注释“1.0.2”必须切到1.0.2版“>1.0.2”必须大于1.0.2版“>1.0.…...

Elasticsearch7.8.0版本进阶——多文档操作流程

目录一、多文档操作1.1、多文档操作的概述1.2、多文档操作与单文档模式区别二、用单个 mget 请求取回多个文档2.1、用单个 mget 请求取回多个文档的图解2.2、用单个 mget 请求取回多个文档的步骤三、bulk API 的模式请求取回多个文档3.1、bulk API 的模式请求取回多个文档的图解…...

Scala函数式编程(第五章:函数基础、函数高级详解)

文章目录第 5 章 函数式编程5.1 函数基础5.1.1 函数基本语法5.1.2 函数和方法的区别5.1.3 函数定义5.1.4 函数参数5.1.5 函数至简原则&#xff08;重点&#xff09;5.2 函数高级5.2.1 高阶函数5.2.2 匿名函数5.2.3 高阶函数案例5.2.4 函数柯里化&闭包5.2.5 递归5.2.6 控制抽…...

ZED相机快速使用指南

1、安装SDK ZED SDK 3.8 - Download | Stereolabs 2、安装ros GitHub - stereolabs/zed-ros-wrapper: ROS wrapper for the ZED SDK 其他教程&#xff1a;ZED2相机SDK安装使用及ROS下使用_可即的博客-CSDN博客 3、官方文档 Get Started with ZED | Stereolabs 4、标定参…...

树莓派4b配置OpenWrt联网

文章目录前言一、下载固件二、配置wan口三、简单介绍1、修改无线名称、设置密码2、下载软件包总结前言 树莓派4b内置wifi模块&#xff0c;加一个千兆网口 好像有一种办法&#xff0c;通过无线wifi链接其他wifi通网&#xff0c;然后把这个网口作为lan口&#xff0c;连接电脑使…...

不同语言下的定时器,你都掌握了吗?

我们大家都对定时器不陌生&#xff0c;无论是现实中还是项目中&#xff0c;都离不开定时。在现实中&#xff0c;它叫闹钟&#xff0c;在项目上&#xff0c;它叫定时器&#xff0c;即定时触发某件事情。它能帮助我们在某一个既定的时间节点上&#xff0c;来提醒我们做一些事情&a…...

华为OD机试 - 水仙花数(Python) | 机试题+算法思路+考点+代码解析 【2023】

水仙花数 题目 所谓的水仙花数是指一个n位的正整数其各位数字的n次方的和等于该数本身, 例如153 = 1^3 + 5^3 + 3^3,153是一个三位数 输入 第一行输入一个整数N, 表示 N 位的正整数 N 在3-7之间包含3,7 第二行输入一个正整数M, 表示需要返回第M个水仙花数 输出描述 返…...

在onBindViewHolder设置View的translation失败或错乱的问题

这个问题&#xff0c;可以换成“为什么在onCreate里面修改一些子View不生效&#xff0c;错位&#xff0c;乱”等问题。 本质原因肯定是在没有把整个ViewGroup渲染完成之前&#xff0c;操作了部分子View&#xff0c;导致了位置偏移等。 解决办法也很简单&#xff0c;通过调用Vi…...

【2.21】MySQL索引、动态规划、学习方法

索引常见面试题 什么是索引 索引的定义就是帮助存储引擎快速获取数据的一种数据结构&#xff0c;形象的说就是索引是数据的目录。存储引擎&#xff0c;说白了就是如何存储数据、如何为存储的数据建立索引和如何更新、查询数据等技术的实现方法。索引和数据就是位于存储引擎。…...

华为OD机试题 - 二叉树层次遍历(JavaScript)| 包含代码编写思路

最近更新的博客 华为OD机试题 - 字符串加密(JavaScript) 华为OD机试题 - 字母消消乐(JavaScript) 华为OD机试题 - 字母计数(JavaScript) 华为OD机试题 - 整数分解(JavaScript) 华为OD机试题 - 单词反转(JavaScript) 华为OD机试题 最近更新的博客使用说明二叉树层次遍…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

汽车生产虚拟实训中的技能提升与生产优化​

在制造业蓬勃发展的大背景下&#xff0c;虚拟教学实训宛如一颗璀璨的新星&#xff0c;正发挥着不可或缺且日益凸显的关键作用&#xff0c;源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例&#xff0c;汽车生产线上各类…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

全志A40i android7.1 调试信息打印串口由uart0改为uart3

一&#xff0c;概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本&#xff1a;2014.07&#xff1b; Kernel版本&#xff1a;Linux-3.10&#xff1b; 二&#xff0c;Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01)&#xff0c;并让boo…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...