C++之模版初阶
目录
前言
1.泛型编程
2.函数模版
2.1函数模版概念
2.2函数模版格式
2.3函数模版的原理
2.4函数模版的实例化
2.5模版参数的匹配原则
3.类模版
3.1类模版的定义格式
3.2类模版的实例化
结束语
前言
前面我们学习了C++的类与对象和内存管理,接下来我们继续学习C++的相关知识!!!
1.泛型编程
泛型编程是一种编程范式,它允许编写与类型无关的代码,从而提高代码的重用性和灵活性。在 C++ 中,泛型编程主要通过模板实现,包括函数模板和类模板。
引入问题->如何实现一个通用的交换函数?
在以前我们都是通过写不同的类型交换函数,
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;
}在这里使用函数重载虽然可以实现,但是有一下几个不好的地方:
1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增 加对应的函数
2. 代码的可维护性比较低,一个出错可能所有的重载均出错
那我们能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
答案当然是可以的!!!

如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同 材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只 需在此乘凉。
即就是我们所要学习的泛型编程。
2.函数模版
2.1函数模版概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生 函数的特定类型版本。
2.2函数模版格式
template<typename T1,typename T2,...typename Tn>
返回值类型 函数名(参数列表){}
注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替 class
例如实现交换函数
template<typename T>
void Swap(T& x, T& y) {T temp = x;x = y;y=temp;
}
int main() {double a = 3.4, b = 4.3;Swap(a, b);cout << a << " " << b << endl;char x = a, y = b;Swap(x, y);cout << x << " " << y << endl;return 0;
}
2.3函数模版的原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。 所以其实模板就是将本来应该我们做的重复的事情交给了编译器 。

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演, 将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
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.0;cout<<Add(a1, a2)<<endl;cout<<Add(d1, d2)<<endl;
}如果计算a1+d1,就会出问题了,即Add(a1, d1);
/* 该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型 通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有 一个T, 编译器无法确定此处到底该将T确定为int 或者 double类型而报错 */
此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化 3.定义多个类
Add(a, (int)d);
Add<int>(a1, d1)
template<class T1,class T2>
T2 Add(const T1& left, const T2& right)
{
return left + right;
}
2.显式实例化
在函数名后的<>中指定模板参数的实际类型。
int main(void){int a = 10;double b = 20.1;// 显式实例化
Add<int>(a, b);return 0;}2.5模版参数的匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这 个非模板函数。
int Add(int x, int y) {return x + y;
}
template<class T1,class T2>
T2 Add(const T1& left, const T2& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.0;cout<<Add(a1, a2)<<endl; 
// 与非模板函数匹配,编译器不需要特化cout << Add<int>(a1, a2) << endl;
//调用编译器特化的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. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。
int Add(int x, int y) {return x + y;
}
/*
template<class T1,class T2>
T2 Add(const T1& left, const T2& right)
{return left + right;
}
*/
int main()
{int a1 = 10, a2 = 20;double d1 = 10.1, d2 = 20.0;//cout<<Add(a1, a2)<<endl;//cout << Add<int>(a1, a2) << endl;cout << Add(a1, d1) << endl;//cout<<Add(d1, d2)<<endl;
}3.类模版
3.1类模版的定义格式
template<class T1,classT2,...class Tn>
class 类模板名
{ // 类内成员定义 };
下面我们实现一个栈的类模版
#include <iostream>
#include <cassert>
using namespace std;
template<class T>
class Stack {
public:Stack(size_t n = 4) :_arr(new T[n]),_size(0),_capacity(n){}~Stack() {delete[] _arr;_arr = nullptr;_size = _capacity = 0;}void push(const T& x) {if (_size == _capacity) {T* temp = new T[_capacity * 2];memcpy(temp, _arr, sizeof(T) * _size);delete[]_arr;_arr = temp;_capacity = _capacity * 2;}_arr[_size++] = x;}void pop() {assert(_arr);assert(_size>0);_size--;}T top() {assert(_arr);assert(_size > 0);return _arr[_size - 1];}bool empty()const {return _size == 0;}
private:T* _arr;size_t _size;size_t _capacity;
}; 
int main() {//类模版都是显式实例化Stack <int>s1;s1.push(1);s1.push(2);s1.push(3);s1.push(4);while (!s1.empty()) {cout << s1.top()<<endl;s1.pop();}Stack <double>s2;s2.push(1.1);s2.push(2.2);s2.push(3.3);s2.push(4.4);while (!s2.empty()) {cout << s2.top() << endl ;s2.pop();}return 0;
}相较于C语言的typedef定义数据类型(只能实现一种数据栈),这里我们可以实现多种数据类型栈。

3.2类模版的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的 类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// Stack是类名,Stack<int>才是类型
Stack <int>s1;
Stack<double>s2;
如果我们想在类外实现Stack的构造等部分引用了类模版的函数,如果只是单纯的函数声明是仅仅不够的,我们还要再次定义一个类模版。
例如:
template<class T>
void Stack<T>:: push(const T& x) {if (_size == _capacity) {T* temp = new T[_capacity * 2];memcpy(temp, _arr, sizeof(T) * _size);delete[]_arr;_arr = temp;_capacity = _capacity * 2;}_arr[_size++] = x;
}结束语
本期内容就到此结束,关于模版进阶的内容后续会讲解的,下节我们将对STL进行一些说明,
最后感谢各位友友的支持,点个赞吧!!!
相关文章:
 
C++之模版初阶
目录 前言 1.泛型编程 2.函数模版 2.1函数模版概念 2.2函数模版格式 2.3函数模版的原理 2.4函数模版的实例化 2.5模版参数的匹配原则 3.类模版 3.1类模版的定义格式 3.2类模版的实例化 结束语 前言 前面我们学习了C的类与对象和内存管理,接下来我们继续学习…...
飞桨paddle API函数scatter详解
飞桨的scatter函数,是通过基于 updates 来更新选定索引 index 上的输入来获得输出,具体官网api文档见: scatter-API文档-PaddlePaddle深度学习平台 官网给的例子如下: >>> import paddle>>> x paddle.to_tens…...
 
RCE漏洞复现
PHP命令执行常用函数 回调函数必须是命令执行和代码执行的函数,有两个条件 必须是函数,而且需要有函数运行的参数 危害:可以直接删除文件,添加文件,甚至可以添加用户 system --执行外部程序,并且显示输…...
 
Qt QTabWidget之创建标签页的多页面切换
QTabWidget 用来分页显示 重要函数: 1.void setTabText(int, QString); //设置页面的名字. 2.void setTabToolTip(QString); //设置页面的提示信息. 3.void setTabEnabled(bool); //设置页面是否被激活. 4.void setTabPosition(QTabPosition::South); //设置页面名字的位置. 5.…...
 
【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出
【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出 文章目录 【RISC-V设计-14】- RISC-V处理器设计K0A之打印输出1.简介2.验证用例3.软件代码4.链接脚本5.编译脚本6.仿真结果6.1 复位结束6.2 运行成功6.3 终端打印 7.总结 1.简介 本文将详细阐述如何利用 printf 来打印字符串…...
 
时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention
时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention 文章目录 前言时序预测|基于变分模态分解-时域卷积-双向长短期记忆-注意力机制多变量时间序列预测VMD-TCN-BiLSTM-Attention 一、VMD-TCN-BiLSTM-Attention模型1. **…...
Python知识点:如何使用Godot与Python进行游戏脚本编写
在Godot中使用Python进行游戏脚本编写,你需要通过一个插件来实现,因为Godot原生支持的脚本语言是GDScript、VisualScript和C#。这个插件被称为Godot-Python,它允许你在Godot引擎中使用Python编写脚本。以下是详细的步骤指导你如何配置和使用G…...
 
Spring MVC数据绑定和响应学习笔记
学习视频:12001 数据绑定_哔哩哔哩_bilibili 目录 1.数据绑定 简单数据绑定 默认类型数据绑定 简单数据类型绑定的概念 参数别名的设置 PathVariable注解的两个常用属性 POJO绑定 自定义类型转换器 xml方式 注解方式 数组绑定 集合绑定 复杂POJO绑定 属性为对象类…...
 
Vulnhub JIS-CTF靶机详解
项目地址 https://www.vulnhub.com/entry/jis-ctf-vulnupload,228/https://www.vulnhub.com/entry/jis-ctf-vulnupload,228/ 修改靶机的网卡 开机时长按shift,进入此页面 选择root模式进入 将只读模式改为读写模式 mount -o remount,rw / 查看本机的网卡名称 …...
 
FPGA资源评估
FPGA资源评估 文章目录 FPGA资源评估前言一、资源评估1.1 资源有哪些1.2 资源统计 二、 FPGA 的基本结构三、 更为复杂的 FPGA 架构 前言 一、资源评估 大家在项目中一般会要遇到需要资源评估的情况,例如立了新项目,前期需要确定使用什么FPGA片子&…...
REST framework中Views API学习
REST framework提供了一个APIView类,它是Django的View类的子类。 APIView类和一般的View类有以下不同: 被传入到处理方法的请求不会是Django的HttpRequest类的实例,而是REST framework的Request类的实例。处理方法可以返回REST framework的…...
Vue(四)——总结
渐进式JavaScript框架 Vue.js是一套构建用户界面(UI)的渐进式JavaScript框架。 1、库和框架的区别? 库:库是提供给开发者的一个封装好的特定于某一方面的集合(方法和函数),库没有控制权&…...
 
计算机毕业设计 招生宣传管理系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试
🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点…...
 
练习题PHP5.6+变长参数 ⇒ usort回调后门 ⇒ 任意代码执行
突破长度限制 使用usort上传后门 usort — 使用用户自定义的比较函数对数组中的值进行排序 paramusort(...$GET); ...为php设置可变长参数 在url地址栏中输入[]test&1[]phpinfo();&2assert 包含了phpiinfo()命令执行 结合usort使用 assert…...
 
EPLAN关于PLC的输入输出模块绘制
EPLAN关于PLC的输入输出模块绘制 总览图上的PLC绘制原理图上的PLC绘制编辑IO注释显示总览界面IO注释自动关联总览IO地址 总览图上的PLC绘制 右键项目【新建】 页类型选择【总览】,描述可以自由编辑,之后确认即可。 由于我们需要绘制PLC的输入输出&#x…...
 
【Linux】sersync 实时同步
原理 rsync 是不支持实时同步的,通常我们借助于 inotify 这个软件来实时监控文件变化,一旦inotify 监控到文件变化,则立即调用 rsync 进行同步,推送到 rsync 服务端。 环境准备 步骤1:获取数据包 获取 sersync 的包…...
 
Unity 资源分享 之 恐龙Ceratosaurus资源模型携 82 个动画来袭
Unity 资源分享 之 恐龙Ceratosaurus资源模型携 82 个动画来袭 一、前言二,资源包内容三、免费获取资源包 一、前言 亲爱的 Unity 开发者和爱好者们,大家好!今天要为大家分享一份超级酷炫的 Unity 资源——恐龙资源模型,而且它还…...
 
【AI绘画】 学习内容简介
AI绘画-学习内容简介 1. 效果展示 本次测试主要结果展示如下: 卡通手办定制1 卡通手办定制2 艺术写真定制 2. 主要目录 AI 绘画- 文生图,图生图及lora使用(基于diffusers) AI 绘画- 模型转换与快速生图(基于diffus…...
 
树形结构查找(B树、B+树)
平衡树结构的树高为 O(logn) ,平衡树结构包括两种平衡二叉树结构(分别为 AVL 树和 RBT)以及一种树结构(B-Tree,又称 B 树,它的度大于 2 )。AVL 树和 RBT 适合内部存储的应用,而 B 树…...
 
网络通信(TCP/UDP协议 三次握手四次挥手 )
三、TCP协议与UDP协议 1、TCP/IP、TCP、 UDP是什么 TCP/IP协议是一个协议簇,里面包括很多协议的, UDP只是其中的一个, 之所以命名为TCP/IP协议, 因为TCP、 IP协议是两个很重要的协议,就用他两命名了,而TCP…...
 
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
 
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
 
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
C++.OpenGL (10/64)基础光照(Basic Lighting)
基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
 
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
 
【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
 
Linux部署私有文件管理系统MinIO
最近需要用到一个文件管理服务,但是又不想花钱,所以就想着自己搭建一个,刚好我们用的一个开源框架已经集成了MinIO,所以就选了这个 我这边对文件服务性能要求不是太高,单机版就可以 安装非常简单,几个命令就…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...
