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

C++:初识函数模板和类模板

目录

一. 泛型编程

二. 函数模板

2.1 什么是函数模板

2.2 函数模板的实例化

2.2.1 函数模板的隐式实例化

2.2.1 函数模板的显示实例化

2.3 函数模板实例化的原理

2.4 模板函数调用实例化原则

三. 类模板

3.1 什么是类模板

3.2 类模板的实例化


一. 泛型编程

泛型编程,就是编写与类型无关的通用代码,使同一段代码可以适用于所有类型的数据。如:编写一个Swap函数,使其可以实现对所有内置类型数据的交换、编写一个链表类List,使其能够适用于存储所有数据类型的链表。

之前,如果我们想要编写支持所有数据类型的Swap函数,就需要编写多个重载函数,如:Swap(int& x, int& y)、Swap(double& x, double& y)。但是,函数重载会造成大量的代码冗余,而良好的代码对冗余是非常忌讳的。为了避免代码冗余,实现编写一份代码就适用于所有类型的数据,C++引入了模板的概念,而模板就是实现泛型编程的基础。

C++中的模板分为函数模板和类模板,由于C语言不支持模板,所有C语言也不支持泛型编程。

图1.1  C++模板分类

二. 函数模板

2.1 什么是函数模板

函数模板,本质上来说就是一个函数家族,在调用函数时,根据函数模板实例化出具体的函数,函数模板与参数类型无关。

定义函数模板的格式:

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

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

typename是函数模板关键字,可以使用class来替代,但不能使用struct来替代。

演示代码2.1以Swap函数为例,编写了一个Swap函数的函数模板,这个Swap函数可以对任何内置类型数据进行交换操作。

演示代码2.1:Swap函数模板

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

2.2 函数模板的实例化

根据实例化函数模板时是否指定参数类型,可分为隐式实例化和显示实例化。

2.2.1 函数模板的隐式实例化

隐式实例化,就是在调用函数时,不指定函数参数和返回值的类型,通过传入的数据,让编译器自己去推断类型。

演示代码2.2以Swap函数为例,分别向函数中传入了两个int型数据和两个double型数据进行交换,输出交换后的结果。根据输出结果可见,Swap函数模板成功对int型数据和double型数据进行了交换,证实了函数模板的通用性。

演示代码2.2:

int main()
{int a1 = 10, a2 = 20;double d1 = 10.11, d2 = 20.22;Swap(a1, a2);cout << "a1 = " << a1 << ", " << "a2 = " << a2 << endl;Swap(d1, d2);cout << "d1 = " << d1 << ", " << "d2 = " << d2 << endl;return 0;
}
图2.2 演示代码2.2的运行结果

2.2.1 函数模板的显示实例化

假设,我们传入一个int型参数和一个double型参数,试图实例化函数模板Swap:Swap(a1, d2)。当编译器看到a1时,会将T推断为int型数据,当编译器看到d2时,会将T推断为double型数据。但是,由于函数的模板参数列表中只有一个T,而一个T不能表示两种类型的数据,因此,这里会编译失败。

如果我们确实希望通过演示代码2.1中定义的Swap函数模板,实现int型数据和double型数据之间的数据交换,有以下两种方式可以实现:

  • 强制类型转换:Swap(a1, (int)d1) 
  • 显示实例化:Swap<int>(a1, d1)

函数模板的显示实例化,就是通过在函数调用时,在函数名后面添加<模板参数类型>,显示地指定模板参数类型,从而省去了编译器自动推断模板参数类型的过程。

演示代码2.3定义了加法Add的函数模板,通过显示指定模板参数的类型为int和double进行调用,分别完成了整形数据和浮点型数据的加法操作。

演示代码2.3:

template<typename T>
T Add(T x, T y)
{return x + y;
}int main()
{int a = 10;double d = 20.2;cout << Add<int>(a, d) << endl;cout << Add<double>(a, d) << endl;return 0;
}

2.3 函数模板实例化的原理

函数模板其实并不是一个具体的函数,它相当于浇注制造中用到的模具,可用于生成具体的函数,但其本身不是函数。当要通过函数模板调用函数时,我们会传入模板参数,编译器则会根据模板参数类型,利用函数模板实例化出具体的函数。

如Swap函数,我们先后用它来交换char类型、int型和double型数据,编译器就会生成3个重载函数:void Swap(char& x, char& y)、void Swap(int& x, int& y)和void Swap(double& x, double& y),这三个函数存储在内存中不同的位置。 

图2.3 函数模板实例化的原理

2.4 模板函数调用实例化原则

  • 模板函数可以与非模板函数同名。
  • 如果非模板函数能够很好地匹配调用参数的类型,那么编译器会优先调用非模板函数而不是根据函数模板实例化出函数来调用。
  • 模板函数在传参时不允许存在隐式类型转换,但非模板函数允许隐式类型转换。

三. 类模板

3.1 什么是类模板

类模板与函数模板类似,通过模板参数列表,来使类中的成员函数参数和成员变量可以为任何想要的数据类型。

类模板的定义格式:

template<typename T1, typename T2, ... , typename n)

class 类名

{

        成员函数列表 ......

        成员变量列表 ......

}

演示代码3.1以栈类为例,定义了一个可以实例化为存储任何数据类型的栈。其中包括4个显示定义的成员函数:构造、析构、压栈和打印,包括三个成员变量:指向存储数据内存区域的指针_a、栈顶下标_top、栈容量_capacity。

该栈模板类引入T作为模板参数,其中压栈函数的参数和成员变量_a均涉及参数T,在实例化时,T可以被解析为多种类型(如int、double、char等)。

抛开类模板的实际功能来讲,T还可以实例化为自定义类型,如果T被实例化为自定义类型,那么这创建模板类对象时,会去调用T的构造函数。

演示代码3.1:

template <class T>
class Stack  //栈类
{
public:Stack(int capacity = 10);~Stack();void Push(T x);void Print();private:T* _a;int _top;int _capacity;
};//类模板成员函数定义和声明分离
//函数返回值 类名<模板>::函数名(参数列表)
template <class T>
Stack<T>::Stack(int capacity): _capacity(capacity), _top(0)
{_a = new T[capacity];
}template <class T>
Stack<T>::~Stack()
{delete[] _a;_top = _capacity = 0;
}template <class T>
void Stack<T>::Push(T x)
{_a[_top++] = x;
}template <class T>
void Stack<T>::Print()
{int i = 0;for (i = 0; i < _top; ++i){std::cout << _a[i] << " ";}std::cout << std::endl;
}

3.2 类模板的实例化

与函数模板既可以显示实例化也可以隐式实例化不同,类模板只能显示实例化。即:告知编译器模板参数的类型。

类模板实例化格式:类名<模板参数类型> 对象名

演示代码3.2展示了对于栈类模板的实例化,分别实例化处一个int栈对象st1和double栈对象st2,对两个栈进行压栈操作并打印栈中数据,证实了该栈类模板能够适用于各种数据类型的栈。

演示代码3.2:

int main()
{//函数模板可以显示调用也可以隐式调用//但类模板只能显示调用Stack<int> st1;st1.Push(1);st1.Push(2);st1.Push(3);st1.Print();Stack<double> st2;st2.Push(1.1);st2.Push(2.2);st2.Push(3.3);st2.Print();return 0;
}
图3.2 演示代码3.2的运行结果

 

相关文章:

C++:初识函数模板和类模板

目录 一. 泛型编程 二. 函数模板 2.1 什么是函数模板 2.2 函数模板的实例化 2.2.1 函数模板的隐式实例化 2.2.1 函数模板的显示实例化 2.3 函数模板实例化的原理 2.4 模板函数调用实例化原则 三. 类模板 3.1 什么是类模板 3.2 类模板的实例化 一. 泛型编程 泛型编程…...

3.8妇女节如何做好TikTok网红营销?

3月8日是国际妇女节&#xff0c;这一节日已经成为全球关注女性权益和平等的标志性日子&#xff0c;TikTok上话题#internationalwomensday累计播放超10亿次&#xff0c;话题#WomensDay2023累计播放量也将近300万次。 这个特别的日子为品牌提供了一个很好的营销机会。据Nox聚星了…...

使用Advanced Installer打包程序及运行环境

Advanced Installer 工具版本&#xff1a;20.1.1 设置产品信息 选中右侧【Product Details】输入产品信息 设置文件和文件夹 添加使用VS发布之后的程序文件夹 设置文件夹刷新 选中文件夹&#xff0c;右键选择属性&#xff0c;选中Synchronize标签。启用“Synchronize conten…...

华为OD机试真题Python实现【计算堆栈中的剩余数字】真题+解题思路+代码(20222023)

计算堆栈中的剩余数字 题目 向一个空栈中依次存入正整数 假设入栈元素N(1<=N<=2^31-1) 按顺序依次为Nx … N4、N3、N2、N1, 当元素入栈时,如果N1=N2+...Ny(y的范围[2,x],1 <= x <= 1000) 则 N1 到 Ny 全部元素出栈,重新入栈新元素M(M=2*N1) 如依次向栈存储6、1、…...

企业文件数据泄露防护(DLP)

什么是数据丢失防护 数据丢失防护 &#xff08;DLP&#xff09; 是保护数据不落入坏人之手的做法。如今&#xff0c;数据传输的主要问题是使大量数据容易受到未经授权的传输。通过设置足够的安全边界&#xff0c;您可以控制数据在网络中的移动。由于您的数据非常有价值&#x…...

不考虑分配与合并情况下,GO实现GCMarkSweep(标记清楚算法)

观前提醒 熟悉涉及到GC的最基本概念到底什么意思&#xff08;《垃圾回收的算法与实现》&#xff09;我用go实现&#xff08;因为其他的都忘了&#xff0c;(╬◣д◢)&#xff91;&#xff77;&#xff70;!!&#xff09; 源码地址&#xff08;你的点赞&#xff0c;是我开源的…...

利用HGT聚类单细胞多组学数据并推理生物网络

单细胞多组学数据允许同时对多种组学数据进行定量分析&#xff0c;以捕捉复杂的分子机制和细胞异质性。然而现有的工具不能有效地推断不同细胞类型的活性生物网络以及这些网络对外部刺激的反应。 来自&#xff1a;Single-cell biological network inference using a heterogen…...

杂记——18.VSCode的下载及使用

这篇文章&#xff0c;我们来讲一下VSCode&#xff0c;讲一下如何下载及使用VSCode 目录 1.VSCode的下载 1.1VSCode的简介 1.2VSCode的下载与安装 1.2.1下载 1.2.2安装 2.VSCode的使用 2.1界面 2.2基础设置 2.3禁用自动更新 2.3自动保存设置 2.4Vscode更换主题 2.5…...

【独家】华为OD机试 - 最少停车数(C 语言解题)

最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 最近更新的博客使用说明本期…...

顶级动漫IP加持之下,3A策略游戏Mechaverse如何改变GameFi

2021年是元宇宙发展的元年&#xff0c;元宇宙与GameFi创造了一波又一波市场热点。在经历第一波热潮之后&#xff0c;元宇宙的到来让不少人看到了加密市场的潜力&#xff0c;同时大家也意识到这将是未来的重要方向。如何将元宇宙推向更广阔的市场&#xff0c;让更多人能够轻松进…...

一款丧心病狂的API测试工具:Apifox!

你好&#xff0c;我是测试开发工程师——凡哥。欢迎和我交流测试领域相关问题&#xff08;测试入门、技术、python交流都可以&#xff09; 我们平时在做接口测试的时候&#xff0c;对于一些常用的接口测试工具的使用应该都非常熟悉了&#xff1a; 接口文档&#xff1a;Swagge…...

【前端学习】D2-2:CSS基础

文章目录前言系列文章目录1 Emmet语法1.1 快速生成HTML语法结构1.2 快速生成CSS样式语法1.3 快速格式化代码2 CSS复合选择器2.1 什么是复合选择器2.2 后代选择器&#xff08;*&#xff09;2.3 子选择器2.4 并集选择器&#xff08;*&#xff09;2.5 伪类选择器2.6 链接伪类选择器…...

Flink / Scala 实战 - 19.ProcessFunction 删除 key 的上一个定时器 TimeTimer

一.引言 ProcessFunction 原始执行状态为每个 key 注册一个较长时间 TimeTimer 并在这期间将所有对应 key 的数据都收集起来,到期完成触发。现在接到新的需求,要求判断数据类型,当特殊标识的数据到达后,需要将 TimeTimer 到期的时间提前。因此需要删掉当前 key 之前注册的老…...

MSTP基础

MSTP基础引入背景技术概览PVSTP&#xff08;过渡&#xff09;MSTP单生成树的缺陷1&#xff1a;部分VLAN不通单生成树的缺陷2&#xff1a;无法实现流量的负载分担多生成树解决单生成树实例引入背景 RSTP在STP基础上进行了改进&#xff0c;实现了网络拓扑快速收敛。但由于局域网…...

当ChatGPT遇见stable-diffusion,你不敢相信的创意艺术之旅!

前言 欢迎来到一场创意的旅程&#xff0c;这里将聚焦于 ChatGPT 和 stable-diffusion 这两个令人激动的技术。在这篇文章中&#xff0c;我们将会探索这两种技术如何结合使用&#xff0c;为艺术创作带来全新的可能性。我们将探讨如何利用 ChatGPT 生成富有想象力的创意&#xf…...

一文搞定!postman接口自动化测试【附项目实战详解】

目录&#xff1a;导读 | 接口结果判断 功能区 脚本相关 代码模板 | 集合(批量)测试 变化的参数数据 定期任务 接口执行顺序 数据传递 | 解决依赖问题 假设场景 Postman 中的操作 运行 写在最后 附带项目实战教程地址&#xff1a;postman接口自动化测试使用教程项…...

ctfshow【菜狗杯】wp

文章目录webweb签到web2 c0me_t0_s1gn我的眼里只有$抽老婆一言既出驷马难追TapTapTapWebshell化零为整无一幸免无一幸免_FIXED传说之下&#xff08;雾&#xff09;算力超群算力升级easyPytHon_P遍地飘零茶歇区小舔田&#xff1f;LSB探姬Is_Not_Obfuscateweb web签到 <?ph…...

旋转数组的几种做法

千淘万浪虽辛苦&#xff0c;吹尽黄沙始到金。 ——刘禹锡 第一种方法&#xff1a;遍历整个数组 题目描述&#xff1a; 一个数组A中存有N (N>0) 个整数&#xff0c;允许使用另外数组&#xff0c;将每个整数循环向右移动M(M>0)个位置。如果需要…...

创建虚拟机、添加镜像以及配置虚拟机

一、创建虚拟机 1、点击 “创建新的虚拟机” 2.选择“自定义配置” 到后面可以选择硬件的类型 3.默认值就行 4.选择 “稍后安装操作系统” 5.操作系统选择 “Linux”&#xff0c;版本结合镜像自行选择 6. 虚拟机的名称自行定义&#xff0c; 就是上述显示出来的名称。 虚拟机…...

Godot Engine 4.0横空出世,Vulkan大怪兽加持,画质提升简直亮瞎眼

【CSDN 编者按】经历了漫长的等待&#xff0c;万众瞩目的 Godot Engine 4.0 正式版在其 3.0 版本发布 5 年以后&#xff0c;终于带着海量令人兴奋的新功能横空出世&#xff01; 整理 | 开发游戏的老王 责编 | 王子彧 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

代码规范和架构【立芯理论一】(2025.06.08)

1、代码规范的目标 代码简洁精炼、美观&#xff0c;可持续性好高效率高复用&#xff0c;可移植性好高内聚&#xff0c;低耦合没有冗余规范性&#xff0c;代码有规可循&#xff0c;可以看出自己当时的思考过程特殊排版&#xff0c;特殊语法&#xff0c;特殊指令&#xff0c;必须…...

省略号和可变参数模板

本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...

Python 高效图像帧提取与视频编码:实战指南

Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

【UE5 C++】通过文件对话框获取选择文件的路径

目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 &#xff0c;这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器&#xff0c;右键点击 .uproject 文件&#xff0c;选择 "Generate Visual Studio project files"&#xff0c;重…...