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

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的类与对象和内存管理&#xff0c;接下来我们继续学习…...

飞桨paddle API函数scatter详解

飞桨的scatter函数&#xff0c;是通过基于 updates 来更新选定索引 index 上的输入来获得输出&#xff0c;具体官网api文档见&#xff1a; scatter-API文档-PaddlePaddle深度学习平台 官网给的例子如下&#xff1a; >>> import paddle>>> x paddle.to_tens…...

RCE漏洞复现

PHP命令执行常用函数 回调函数必须是命令执行和代码执行的函数&#xff0c;有两个条件 必须是函数&#xff0c;而且需要有函数运行的参数 危害&#xff1a;可以直接删除文件&#xff0c;添加文件&#xff0c;甚至可以添加用户 system --执行外部程序&#xff0c;并且显示输…...

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进行游戏脚本编写&#xff0c;你需要通过一个插件来实现&#xff0c;因为Godot原生支持的脚本语言是GDScript、VisualScript和C#。这个插件被称为Godot-Python&#xff0c;它允许你在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&#xff0c;进入此页面 选择root模式进入 将只读模式改为读写模式 mount -o remount,rw / 查看本机的网卡名称 …...

FPGA资源评估

FPGA资源评估 文章目录 FPGA资源评估前言一、资源评估1.1 资源有哪些1.2 资源统计 二、 FPGA 的基本结构三、 更为复杂的 FPGA 架构 前言 一、资源评估 大家在项目中一般会要遇到需要资源评估的情况&#xff0c;例如立了新项目&#xff0c;前期需要确定使用什么FPGA片子&…...

REST framework中Views API学习

REST framework提供了一个APIView类&#xff0c;它是Django的View类的子类。 APIView类和一般的View类有以下不同&#xff1a; 被传入到处理方法的请求不会是Django的HttpRequest类的实例&#xff0c;而是REST framework的Request类的实例。处理方法可以返回REST framework的…...

Vue(四)——总结

渐进式JavaScript框架 Vue.js是一套构建用户界面&#xff08;UI&#xff09;的渐进式JavaScript框架。 1、库和框架的区别&#xff1f; 库&#xff1a;库是提供给开发者的一个封装好的特定于某一方面的集合&#xff08;方法和函数&#xff09;&#xff0c;库没有控制权&…...

计算机毕业设计 招生宣传管理系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…...

练习题PHP5.6+变长参数 ⇒ usort回调后门 ⇒ 任意代码执行

突破长度限制 使用usort上传后门 usort — 使用用户自定义的比较函数对数组中的值进行排序 paramusort(...$GET); ...为php设置可变长参数 在url地址栏中输入[]test&1[]phpinfo();&2assert 包含了phpiinfo&#xff08;&#xff09;命令执行 结合usort使用 assert…...

EPLAN关于PLC的输入输出模块绘制

EPLAN关于PLC的输入输出模块绘制 总览图上的PLC绘制原理图上的PLC绘制编辑IO注释显示总览界面IO注释自动关联总览IO地址 总览图上的PLC绘制 右键项目【新建】 页类型选择【总览】&#xff0c;描述可以自由编辑&#xff0c;之后确认即可。 由于我们需要绘制PLC的输入输出&#x…...

【Linux】sersync 实时同步

原理 rsync 是不支持实时同步的&#xff0c;通常我们借助于 inotify 这个软件来实时监控文件变化&#xff0c;一旦inotify 监控到文件变化&#xff0c;则立即调用 rsync 进行同步&#xff0c;推送到 rsync 服务端。 环境准备 步骤1&#xff1a;获取数据包 获取 sersync 的包…...

Unity 资源分享 之 恐龙Ceratosaurus资源模型携 82 个动画来袭

Unity 资源分享 之 恐龙Ceratosaurus资源模型携 82 个动画来袭 一、前言二&#xff0c;资源包内容三、免费获取资源包 一、前言 亲爱的 Unity 开发者和爱好者们&#xff0c;大家好&#xff01;今天要为大家分享一份超级酷炫的 Unity 资源——恐龙资源模型&#xff0c;而且它还…...

【AI绘画】 学习内容简介

AI绘画-学习内容简介 1. 效果展示 本次测试主要结果展示如下&#xff1a; 卡通手办定制1 卡通手办定制2 艺术写真定制 2. 主要目录 AI 绘画- 文生图&#xff0c;图生图及lora使用&#xff08;基于diffusers&#xff09; AI 绘画- 模型转换与快速生图&#xff08;基于diffus…...

树形结构查找(B树、B+树)

平衡树结构的树高为 O(logn) &#xff0c;平衡树结构包括两种平衡二叉树结构&#xff08;分别为 AVL 树和 RBT&#xff09;以及一种树结构&#xff08;B-Tree&#xff0c;又称 B 树&#xff0c;它的度大于 2 &#xff09;。AVL 树和 RBT 适合内部存储的应用&#xff0c;而 B 树…...

网络通信(TCP/UDP协议 三次握手四次挥手 )

三、TCP协议与UDP协议 1、TCP/IP、TCP、 UDP是什么 TCP/IP协议是一个协议簇&#xff0c;里面包括很多协议的&#xff0c; UDP只是其中的一个&#xff0c; 之所以命名为TCP/IP协议&#xff0c; 因为TCP、 IP协议是两个很重要的协议&#xff0c;就用他两命名了&#xff0c;而TCP…...

C# ADO.Net 通用按月建表插入数据

原理是获取原表表结构以及索引动态拼接建表SQL&#xff0c;如果月表存在则不创建&#xff0c;不存在则创建表结构 代码如下 /// <summary>/// 根据指定的表名和时间按月进行建表插入&#xff08;如果不存在对应的月表&#xff09;/// </summary>/// <param nam…...

19-ESP32-C3加大固件储存区

1默认编译情况。 2、改flash4M。ESP-IDF Partition Table Editor修改。 3、设置输入Partition Table 改自定义.CSV。保存。 4、查看命令输入Partition Table Editor打开-分区表编辑器UI。按图片增加。 nvs,data,nvs,0x9000,0x6000,, phy_init,data,phy,0xF000,0x1000,, factory…...

【STL】stack/queue 容器适配器 deque

1.stack的介绍和使用 1.1.stack的介绍 1. stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。 2. stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容…...

(回溯) LeetCode 17. 电话号码的组合

原题链接 一. 题目描述 17. 电话号码的字母组合 已解答 中等 相关标签 相关企业 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对…...

Ghidra:开源软件逆向工程框架

Ghidra 是一个软件逆向工程 (SRE) 框架 Ghidra 是一种尖端的开源软件逆向工程 (SRE) 框架&#xff0c;是美国国家安全局 (NSA) 研究局的产品。 Ghidra 该框架具有高端软件分析工具&#xff0c;使用户能够分析跨各种平台&#xff08;包括 Windows、macOS 和 Linux&#xff09…...

Spring AI 更新:支持OpenAI的结构化输出,增强对JSON响应的支持

就在昨晚&#xff0c;Spring AI发了个比较重要的更新。由于最近OpenAI推出了结构化输出的功能&#xff0c;可确保 AI 生成的响应严格遵守预定义的 JSON 模式。此功能显着提高了人工智能生成内容在现实应用中的可靠性和可用性。Spring AI 紧随其后&#xff0c;现在也可以对OpenA…...

java.util.ConcurrentModificationException 并发修改异常

目录 异常代码片段 详细说明 解决方案 使用迭代器进行遍历 使用临时集合存储结果 异常代码片段 if (ObjectUtil.isNotEmpty(candidateUsers)) {candidateUsers candidateUsers.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList());for (String …...

Flask数据库操作(第四阶段)

目录 Flask数据库操作一、数据库基础1.1 关系型数据库与非关系型数据库选择数据库 二、Flask-SQLAlchemy2.1 安装 Flask-SQLAlchemy2.2 创建数据库模型2.2.1 创建 Flask 应用2.2.2 定义模型 2.3 执行 CRUD 操作2.3.1 创建&#xff08;Create&#xff09;2.3.2 读取&#xff08;…...

C语言问答进阶--5、基本表达式和基本语句

赋值表达式 表达式是什么&#xff1f;表达式是由运算符和操作数组成的式子。 如下的代码 #include "iostream.h" int main() { int a1,b2,sum; cout<<(sumab)<<endl; return 0; } 那么如下的呢&#xff1f; #include "iostream.h" int mai…...

uniapp3.0实现图片上传公用组件上传uni-file-picker,uni.uploadFile

用uniapp3.0的写法组合式api&#xff0c;setup形式封装一个图片上传公用组件&#xff0c;要求 1、使用uni-file-picker选择文件 2、uni.uploadFile上传图片 3、要能支持上传接口动态化 4、支持删除如片列表中已上传项 5、可以预览已上传列表图片 6、支持动态化限制图片格…...

后台管理网站模板下载/中国万网域名查询

不会变量提升&#xff1f; 经常看到有文章说: 用let和const申明的变量不会提升。其实这种说法是不准确的&#xff0c;比如下面代码: var x 1; if(true) {console.log(x);let x 2; } 上述代码会报错Uncaught ReferenceError: Cannot access x before initialization。如果let…...

北京万户网络技术有限公司/windows优化

简介 如何让代码执行得更快,如何充分发挥多核CPU的性能,是程序员需要思考的问题. 本文通过简单易懂的实例,让大家快速了解C#多线程的基本方法. 参考文档:http://www.cnblogs.com/yunfeifei/p/3993401.html实例 using System; using System.Diagnostics; using System.Threading…...

wordpress论坛主题/sem是什么工作

为什么80%的码农都做不了架构师&#xff1f;>>> 在hazelcast的官方文档中&#xff0c;提到了其支持read-through&#xff0c;write-through与write-behind三种模式。查阅资料&#xff0c;最后在oracle的官文中找到了比较靠谱的解释。 read-throug、write-through、…...

找网站开发/开发新客户的十大渠道

S参数描述了RF网络的基本特征&#xff0c;其主要类型有小信号、大信号、脉冲、冷模式和混合模式S参数。 引言 本文延续之前的一系列短文&#xff0c;旨在为非RF工程师讲解RF的奥秘。其中一些RF文章如下&#xff1a;“RF揭秘——了解波反射”&#xff0c;探讨了波反射&#xf…...

企业自助建站/长沙做网站的公司有哪些

弱菜的做法&#xff0c;生成所有子集&#xff0c;然后从集合元素个数少的开始判断。 有一个大坑是&#xff0c;所有的格子都是空地&#xff0c;这种情况下不用放&#xff0c;输出0。 1 #include <algorithm>2 #include <iostream>3 #include <cstring>4 #inc…...

电商网站建设开发/百度平台商家客服电话

作业头 基础题&#xff08;一&#xff09; 6-1本题要求实现一个字符串逆序的简单函数。 函数接口定义&#xff1a; void f( char *p ); 函数f对p指向的字符串进行逆序操作。要求函数f中不能定义任何数组&#xff0c;不能调用任何字符串处理函数。 裁判测试程序样例&#xff1a;…...