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

【C++】C++模板基础知识篇

个人主页 : zxctscl
文章封面来自:艺术家–贤海林
如有转载请先通知

文章目录

  • 1. 泛型编程
  • 2. 函数模板
    • 2.1 函数模板概念
    • 2.2 函数模板格式
    • 2.3 函数模板的原理
    • 2.4 函数模板的实例化
    • 2.5 模板参数的匹配原则
  • 3. 类模板
    • 3.1 类模板的定义格式
    • 3.2 类模板的实例化

1. 泛型编程

实现一个通用的交换函数:

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;
}

在实现不同类型的参数Swap就得写很多个,
用起来太麻烦了。

使用函数重载虽然可以实现,但是有一下几个不好的地方:

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

所以c++就提供了模板,就相当于一个模具,让编译器根据不同的类型利用该模子来生成代码。

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

在这里插入图片描述

2. 函数模板

2.1 函数模板概念

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

2.2 函数模板格式

函数模板传的是类型。

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

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

把上面代码的Swap写成模板就是:

template<class T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}
int main()
{int a = 1, b = 2;Swap(a, b);double d1 = 1.1, d2 = 2.2;Swap(d1, d2);return 0;
}

在这里插入图片描述
这样就不用每次换一个类型就再写一个函数了。
那么他们调用的函数是同一个吗?
其他并不是。在调试的时候进去的确实是void Swap(T& x, T& y),这个只是编译器方便调试所展示出来的。
编译器会根据用户的调用,推出T的类型,生成类似T类型的Swap。如果用户传的是int,那么T就是int,生成类似int类型的Swap。
在这里插入图片描述

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

2.3 函数模板的原理

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

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

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

所以之后写swap时候直接就能用
在这里插入图片描述

2.4 函数模板的实例化

编译通过推出类型,用函数模板,生成对应的函数,这个过程叫做模板实例化。
用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。

  1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;cout << Add(a1, a2) << endl;cout << Add(a1, a2) << endl;cout << Add(a1, d2) << endl;return 0;
}

在这里插入图片描述
这里存在歧义,a1传过去T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错。

那么怎么解决呢?
1、用户自己来强制转化
可以将a1强转为double
或者将d2强转为int,反正结果不一样。
在这里插入图片描述
2、使用显式实例化,那么怎么用呢?
显式实例化:在函数名后的<>中指定模板参数的实际类型
想要什么类型就用什么在函数名后的<>加什么类型。

在这里插入图片描述
如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

3、写多个参数的模板(一般不用)

template<class T1, class T2>
T1 Add(T1 left, T2 right)
{return left + right;
}

一般是两个类型谁的类型更大,就是谁。但一般不会让两个不同类型的变量相加的。
在这里插入图片描述

2.5 模板参数的匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int Add(const int& left, const int& right)
{return left + right;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.2;cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;return 0;
}

没有模板时候隐式类型转换能用,
两个同时存在时候有没有歧义呢?
编译器有个原则:
1、有现成,吃用成的 (匹配)
2、有现成的,但是不够匹配,有模板,就会选择自己实例化模板
在这里插入图片描述

  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
// 专门处理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函数
}
  1. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3. 类模板

3.1 类模板的定义格式

模板有多个参数时,用“,”分隔。

template<class T1, class T2, ..., class Tn>
class 类模板名
{// 类内成员定义
}; 
template<class T>
class Stack
{
public:void push(const T& x){//...}private:T* _a;int _top;int _capacity;
};int main()
{Stack s1; // intStack s2; // doublereturn 0;
}

模板和typedef有什么区别?
如果typedef能够解决像栈队列这些数据结构的问题,C语言为什么不供,就是语法不好用。
真正解决不了的是给栈里面数据类型不同的时候该怎么做?
在这里插入图片描述
c语言就得写两个类:

typedef int STDataType;
typedef double STDataType;class Stackint
{
public:void push(const STDataType& x){//...}private:STDataType* _a;int _top;int _capacity;
};class Stackdouble
{
public:void push(const STDataType& x){//...}private:STDataType* _a;int _top;int _capacity;
};

在这里插入图片描述

3.2 类模板的实例化

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

emplate<class T>
class Stack
{
public:void push(const T& x);
private:T* _a;int _top;int _capacity;
};int main()
{// 同一个类模板实例化出的两个类型Stack<int> s1;Stack<double> s2;return 0;
}

同一个类模板实例化出的两个类型,只提供模板就行,其他工作是编译器做。

在模板这里得注意一点:在之前普通类类名和类型是一样的,但是模板得加上<>
在这里插入图片描述
类模板不能声明定义分离到两个文件。

有问题请指出,大家一起进步!!!

相关文章:

【C++】C++模板基础知识篇

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 文章目录 1. 泛型编程2. 函数模板2.1 函数模板概念2.2 函数模板格式2.3 函数模板的原理2.4 函数模板的实例化2.5 模板参数的匹配原则 3. 类模板3.1 类模板的定义格式3.2 类模板的实例化…...

golang 注释插件

Goanno插件 自动生成golang注释,该插件为 Intellij/Goland 中的 golang 提供自动生成注释 如何使用&#xff1f; control command / (for windows: control alt /)&#xff08;生成注释&#xff09;Right click -> Generate -> Goanno&#xff08;生成注释&#x…...

Unity插件之天气系统UniStorm

首先呢&#xff0c;它是一款强大的动态昼夜天气系统&#xff0c;能够以较快的帧速率创建AAA级动态生成的天气、照明和天空&#xff0c;并且具有300多个可定制的组件&#xff0c;允许用户创建任何可以想象的环境。 第一步&#xff1a;他需要两个物体Camera摄像机、Player播放器…...

Java使用xlsx-streamer和EasyExcel解决读取超大excel文件数据处理方法

前言 最近有个项目在生产环境做数据导入时&#xff0c;发现开始执行导入任务会出现cpu狂飙的情况。几番定位查找发现是在读取excel的时候导致此问题的发生&#xff0c;因此在通常使用的为POI的普通读取&#xff0c;在遇到大数据量excel&#xff0c;50MB大小或数五十万行的级别的…...

智能驾驶规划控制理论学习04-基于车辆运动学的规划方法

目录 一、线性二自由度汽车模型&#xff08;自行车模型&#xff09; 1、二自由度模型概述 2、不同参考点下的状态空间方程 3、前向仿真 二、运动基元生成方法 1、杜宾斯曲线&#xff08;Dubins Curve&#xff09; 2、Reeds Shepp Curve 三、多项式曲线&#xff08;Poly…...

一键查看:大厂网站都用了啥技术栈,有图有真相。

本次我们采用Wappalyzer插件来看下国内大厂的网站都采用了什么技术架构&#xff0c;文章最后由Wappalyzer的安装方法。 今日头条网站 淘宝网站 哔哩哔哩 京东商城 花瓣网 CSDN 国务院 网易 58同城 腾讯网 如何安装Wappalyzer 用Edge浏览器即可...

C语言-指针(下)

文章目录 前言    文章目录 前言 一、指针运算 1.指针-整数 2.指针-指针 3.指针关系运算 二、野指针 1.概念 2.野指针的成因 1.未初始化 2.指针越界访问 3.指针指向的空间释放 3.避免野指针 1.指针初始化 2.小心指针越界 3. 指针变量不再使用时&#xff0c;及时置NULL 总结 …...

尚硅谷JavaScript高级学习笔记

01 准备 JavaScript中函数是对象。我们后续描述构造函数的内存模型时&#xff0c;会将构造函数称为构造函数对象。 02 数据类型 typeof 运算符来查看值的类型&#xff0c;它返回的是类型的字符串值 会做数据转换 03 相关问题 04数据_变量_内存 05相关问题1 06相关问题2 …...

六、长短时记忆网络语言模型(LSTM)

为了解决深度神经网络中的梯度消失问题&#xff0c;提出了一种特殊的RNN模型——长短期记忆网络&#xff08;Long Short-Term Memory networks, LSTM&#xff09;&#xff0c;能够有效的传递和表达长时间序列中的信息并且不会导致长时间前的有用信息被忽略。 长短时记忆网络原理…...

Filter过滤器+JWT令牌实现登陆验证

一、背景 我们需要在客户端访问服务器的时候给定用户一定的操作权限&#xff0c;比如没有登陆时就不能进行其他操作。如果他需要进行其他操作&#xff0c;而在这之前他没有登陆过&#xff0c;服务端则需要将该请求拦截下来&#xff0c;这就需要用到过滤器&#xff0c;过滤器可以…...

SQL学习十八~十九

...

2024 AI 辅助研发的新纪年

随着人工智能技术的持续发展与突破&#xff0c;2024年AI辅助研发正成为科技界和工业界瞩目的焦点。从医药研发到汽车设计&#xff0c;从软件开发到材料科学&#xff0c;AI正逐渐渗透到研发的各个环节&#xff0c;变革着传统的研发模式。在这一背景下&#xff0c;AI辅助研发不仅…...

【牛客】HJ87 密码强度等级 CM62 井字棋

题目一:密码强度等级 题目链接&#xff1a;密码强度等级_牛客题霸_牛客网 (nowcoder.com) 本题主要考察C语言中逻辑分支语句&#xff0c;基本语句以及对各种特殊字符 &#xff0c;ASCII值以及条件表达中的逻辑运算符关系运算符各自功能的理解&#xff0c;以及基本使用&#x…...

【论文速读】 | DeGPT:通过大语言模型优化反编译器输出

本次分享论文为&#xff1a;DeGPT: Optimizing Decompiler Output with LLM 基本信息 原文作者&#xff1a;Peiwei Hu, Ruigang Liang, Kai Chen 作者单位&#xff1a;中国科学院信息工程研究所&#xff1b;中国科学院大学网络空间安全学院 关键词&#xff1a;反向工程&…...

【DP】蓝桥杯第十三届-费用报销

#include<iostream> #include<algorithm> #include<cstring> #include<set> #include<queue> using namespace std; const int N1010; int dp[N][5010];//dp[i][j]:选到第i个物品是否能取到价值j&#xff1b; int month[13]{0,31,28,31,30,31,30…...

15. C++泛型与符号重载

【泛型编程】 若多组类型不同的数据需要使用相同的代码处理&#xff0c;在C语言中需要编写多组代码分别处理&#xff0c;这样做显然太过繁琐&#xff0c;C增加了虚拟类型&#xff0c;使用虚拟类型可以实现一组代码处理多种类型的数据。 虚拟类型是暂时不确定的数据类型&#…...

老司机都懂的!【打赏】完美运营的最新视频打赏系统

完美运营的最新视频打赏系统优于市面上95%的打赏系统&#xff0c;与其他打赏系统相比&#xff0c;功能更加强大&#xff0c;完美运营且无bug。支付会调、短链接生成、代理后台、价格设置和试看功能等均没有问题。 以上为原简介&#xff0c;经测试验证。成功搭建并可以正常进入…...

JavaWeb笔记 --- 二、Maven

二、Maven Maven概述 所有的IDE创建的Maven项目都可以使用 Maven简介 Maven模型 Maven常用命令 Maven生命周期 Maven坐标 依赖管理 dpendencies&#xff1a;依赖 依赖范围...

【C++】C++11---右值引用和移动语义

目录 1、什么是左值引用和右值引用2、左值引用与右值引用比较3、右值引用使用场景和意义4、右值引用引用左值的分析5、完美转发 1、什么是左值引用和右值引用 传统的C语法中就有引用的语法&#xff0c;而C11中新增了的右值引用语法特性&#xff0c;所以从现在开始我们之前学习…...

消息队列-kafka-消息发送流程(源码跟踪) 与消息可靠性

官方网址 源码&#xff1a;https://kafka.apache.org/downloads 快速开始&#xff1a;https://kafka.apache.org/documentation/#gettingStarted springcloud整合 发送消息流程 主线程&#xff1a;主线程只负责组织消息&#xff0c;如果是同步发送会阻塞&#xff0c;如果是异…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在 GPU 上对图像执行 均值漂移滤波&#xff08;Mean Shift Filtering&#xff09;&#xff0c;用于图像分割或平滑处理。 该函数将输入图像中的…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...