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

C++学习——模板

目录

🍉一:什么是模板

🍎二:普通模板的定义

🍍三:类模板的定义

🍌四:模板的实例化

      🍇1.当普通模板定义存在可修改返回值产生的分歧

  🍈2:类模板实例化声明所需要的注意事项

      🥝Tips:声明类成员函数模板的书写形式

  在C++当中模板可以说是一个很新的东西。因为我们之前根本就没有见过模板,甚至在C语言当中连听都没有听过。所以我们今天就来介绍一下什么是模板以及模板应该怎么使用的。

一:什么是模板

  模板是在C++当中经过引入了函数的重载之后所诞生的一种新的功能。想要详细的了解模板的好处就需要从函数重载的例子开始说起。我们可以来看下面的一段代码:

#include<iostream>//根据函数重载的例子来了解模板的好处
void swap(int& a, int& b)        //交换函数1
{int tmp = a;a = b;b = tmp;
}void swap(double& a, double& b)          //函数重载2
{double tmp = a;a = b;b = tmp;
}void swap(char& a, char& b)         //函数重载3
{char tmp = a;a = b;b = tmp;
}//写一个模板
int main()
{int number1 = 12, number2 = 14;double number3 = 12.12, number4 = 14.14;char ch1 = 'a', ch2 = 'b';//交换前打印各个数据,和交换后的数据进行对比std::cout << "number1=" << number1 << '	' << "number2=" << number2 << std::endl;std::cout << "number3=" << number3 << '	' << "number4=" << number4 << std::endl;std::cout << "ch1=" << number1 << '	' << "ch2=" << ch2 << std::endl;std::cout << std::endl;//通过调用上面的三个重载函数交换我们的数据swap(number1, number2);swap(number3, number4);swap(ch1, ch2);std::cout << "number1=" << number1 << '	' << "number2=" << number2 << std::endl;std::cout << "number3=" << number3 << '	' << "number4=" << number4 << std::endl;std::cout << "ch1=" << number1 << '	' << "ch2=" << ch2 << std::endl;return 0;
}

  就像是我们上面代码中所展示的那样,我们定义了很多交换函数的重载函数,这样可以让我们仅仅调用一个函数就可以交换很多数据类型。但是我们会发现一个弊端,那就是我们虽然在调用的时候减少了麻烦,但是在定义的时候依旧是很麻烦。像是我们上面的代码所示的那样, 每一个函数的大致框架都是相同的,仅仅改变了很少的一部分,所以我们在此时就会想到能不能有一种方式,就是定义出一个大致的模板,我们只需要定义依次这个模板就可以重复使用了呢?于是我们C++当中的模板也就产生了。我们可以将上面的代码进行改写:

#include<iostream>template<typename T>
void swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
int main()
{int number1 = 12, number2 = 14;double number3 = 12.12, number4 = 14.14;char ch1 = 'a', ch2 = 'b';//交换前打印各个数据,和交换后的数据进行对比std::cout << "number1=" << number1 << '	' << "number2=" << number2 << std::endl;std::cout << "number3=" << number3 << '	' << "number4=" << number4 << std::endl;std::cout << "ch1=" << number1 << '	' << "ch2=" << ch2 << std::endl;std::cout << std::endl;//通过调用上面的三个重载函数交换我们的数据swap(number1, number2);swap(number3, number4);swap(ch1, ch2);std::cout << "number1=" << number1 << '	' << "number2=" << number2 << std::endl;std::cout << "number3=" << number3 << '	' << "number4=" << number4 << std::endl;std::cout << "ch1=" << number1 << '	' << "ch2=" << ch2 << std::endl;return 0;
}

  我们会发现使用模板我们可以将上面所有大致相同的代码都概括成为同一段代码进行使用,也可以产生同样的效果。代码运行的效果如下:

  是不是很神奇?既然知道了使用的方法之后就可以来学习模板的使用了,在C++当中模板的定义大致分为两类:普通模板的使用和类模板的使用。接下来我们就来一步一步学习。 

二:普通模板的定义

  普通模板的定义其实就是像我们上面的代码所展示的那样,主要是针对一段相似的代码进行模板化的。通常是针对一个函数的定义。通过代码进行一点一点的分析:

  我们会发现第49行的代码是一段很陌生的代码,除了这一行下面的代码还是很好理解的。就像是我们正常所说的那样,使用一个统一的不特意制定的类型进行替代,也就是我们代码当中的T。我们通过这个T来交换各种类型的数据。话题回到我们的第49行代码。其实这就是定义模板的一种特定的格式。template表示下面的对象是一个模板。后面的 < > 里面是我们想要替换的数据的类型。当然,我们其中的参数并不是只能有一个还可以有多个,但是都需要由一个 typename 引出(也可以是class,class等价于typename)举一个简单的例子:

#include<iostream>//定义一个拥有两个参数的模板
template<typename T1,typename T2>
void test(T1 data1, T2 data2)
{std::cout << "第一类数据:" << '(' << typeid(data1).name() << ") " << data1 << std::endl;std::cout << "第二类数据:" << '(' << typeid(data2).name() << ") " << data2 << std::endl;
}
int main()
{int data1 = 12;char ch = 'a';double data2 = 12.12;int data3 = 99;test(data1, ch);test(data2, data3);return 0;
}

   我们可以使用多个参数实现对应的数据模板化,这样可以让我们的代码变得更加的灵活。那么普通模板的定义学习完毕之后我们再来认识以下类模板的定义。

三:类模板的定义

  对于类模板的定义其实方式和我们的普通模板的定义很相似,但是也有些许的不同。我们通过一段代码来进行学习:

#include<iostream>//定义一个类模板
template<class T1,class T2,class T3>
class test
{
private:T1 data1;T2 data2;T3 data3;
public:void print(){std::cout << typeid(data1).name() << std::endl;std::cout << typeid(data2).name() << std::endl;std::cout << typeid(data3).name() << std::endl;}
};
int main()
{test<int,double,char> t1;t1.print();return 0;
}

  我们可以发现依旧是使用 template 加上 < > 表示下面的内容是一个模板。在表示的时候如果是一个类模板那么在定义变量的时候最好使用class。之后我们就可以书写类,我们只需要将类当中指定的内容替换成为我们在前面声明好的变量名即可。

  但是需要我们注意的是:在使用类模板的时候不能仅仅使用类名进行对象的创建,还应该跟上我们想要赋予的变量类型,这样才可以正常的使用,在后面的模板的实例化我们会有更加详细的总结。 代码运行的结果如下:

四:模板的实例化

  针对于模板的实例化我们想要讲解的是:模板实例化所可能产生的各种情况。

      1.当普通模板定义存在可修改返回值产生的分歧

  作为函数模板我们有时候肯定也会需要将返回值设置成可以随意改变的形式,但是有时候我们又会产生一些分歧,例如:假如我们想要定义一个模板既可以同类型的相加又可以不同类型的数据相加呢?(实例如下)

  这个时候就会产生报错,想要不修改我们的模板类型,又想让我们的程序正常运行的话,就需要使用一点点小小的技巧。

  1.将我们不需要的数据强制类型转换成为另一种数据类型,将两种数据的类型统一。例如:

   2.或者使用一种更高级的方式,例如直接向我们的模板指出我们想要的返回值的类型:

   这两种方式都可以很好的解决我们上面所遇到的问题。除了普通模板的实例化会出现一些些问题之外我们在实例化类模板的时候还会遇到一些问题。

  2:类模板实例化声明所需要的注意事项

  其实说到类模板的实例化,我们可以将其理解为是一个类名想象成为一个没有电的电动车。电动车动起来的核心其实是电,电是必不可少的。所以我们在实例化类模板的时候也是一样。类名是我们的电动车,后面赋予的变量的类型是电。在使用函数模板实例化的时候需要将两者结合起来才能作为一个完整的存在进行使用。这也就是我们上面代码:test<int,double,char> t1; 的意义。test<int,double,char> 表示类的类型,t1表示实例化后的对象名。之后对于实例化所产生的对象的使用和正常相同。

      Tips:声明类成员函数模板的书写形式

  我们在平时书写代码的时候会有一种需求:那就是需要在类中展示的仅仅是声明,而定义需要在另一部分进行。通常情况下的代码的书写的情况是这样的:

#include<iostream>//定义一个类,在类中只声明类的成员函数,在外部进行定义
class Date
{
private:int _year;int _month;int _day;
public:Date(int year = 2022, int month = 12, int day = 12):_year(year), _month(month), _day(day){}void print();
};void Date::print()
{std::cout << _year << "年" << _month << "月" << _day << "日" << std::endl;
}int main()
{Date d1(2023, 1, 1);d1.print();return 0;
}

  在定义类的成员函数的时候需要通过类作用限定符进行特定的指定。我们的模板在外部定义的时候其实是一样的也是需要通过域作用限定符进行专门的指定。但是我们需要注意一点:那就是在使用的时候不能仅仅使用一个“电动车”来指定对象,还需要有“电”。代码示例如下:

  这个时候我们在定义和实例化类生成对象的时候都需要带上我们指定的变量的类型才可以正常的运行。

  那么此上就是我们本次博客的全部内容了,感谢您的观看。 

相关文章:

C++学习——模板

目录 &#x1f349;一&#xff1a;什么是模板 &#x1f34e;二&#xff1a;普通模板的定义 &#x1f34d;三&#xff1a;类模板的定义 &#x1f34c;四&#xff1a;模板的实例化 &#x1f347;1.当普通模板定义存在可修改返回值产生的分歧 &#x1f348;2&#xff1a;类模板实例…...

二叉树的遍历(先序遍历,中序遍历,后序遍历)递归与非递归算法

目录 一、先序遍历题目链接1.递归2.非递归 二、中序遍历题目链接1.递归2.非递归 三、后序遍历题目链接1.递归2.非递归 一、先序遍历 先序遍历&#xff1a;先遍历一颗树的根节点&#xff0c;后遍历左子树&#xff0c;最后遍历右子树 先序遍历序列&#xff1a; 1 -> 2 -> 4…...

【LeetCode】516. 最长回文子序列

文章目录 1. 思路讲解1.1 创建dp表1.2 状态转移方程1.3 不需考虑边界问题 2. 整体代码 1. 思路讲解 1.1 创建dp表 此题采用动态规划的方法&#xff0c;创建一个二维dp表&#xff0c;dp[i][j]表示s[i, j]中最大回文子序列的长度。且我们人为规定 i 是一定小于等于 j 的。 1.2…...

Java 集合框架

Java 集合框架提供了一组接口和类&#xff0c;以实现各种数据结构和算法。 集合框架满足以下几个要求。 该框架必须是高性能的。基本集合&#xff08;动态数组&#xff0c;链表&#xff0c;树&#xff0c;哈希表&#xff09;的实现也必须是高效的。 该框架允许不同类型的集合…...

遇到多人协作,我们该用git如何应对?(版本二)

一、多人协作二 1.1多人协作 一般情况下&#xff0c;如果有多需求需要多人同时进行开发&#xff0c;是不会在一个分支上进行多人开发&#xff0c;而是一个需求或一个功能点就要创建一个feature 分支。 现在同时有两个需求需要你和你的小伙伴进行开发&#xff0c;那么你们俩便…...

Flutter iOS 集成使用 fluter boost

在 Flutter项目中集成完 flutter boost&#xff0c;并且已经使用了 flutter boost进行了路由管理&#xff0c;这时如果需要和iOS混合开发&#xff0c;这时就要到 原生端进行集成。 注意&#xff1a;之前建的项目必须是 Flutter module项目&#xff0c;并且原生项目和flutter m…...

node.js相关的npm包的集合

一、实用功能 1. qs 一个简单易用的字符串解析和格式化库 2.rxjs RxJS是一组模块化的库&#xff0c;用于使用 JavaScript 中的可观察集合和组合来组合异步和基于事件的程序。 3. mitt 微型 200b 功能事件发射器/发布订阅. 4.Underscore.js Underscore.js是一个用于 JavaScript…...

Android Ble蓝牙App(二)连接与发现服务

Ble蓝牙App&#xff08;二&#xff09;连接与发现服务 前言正文一、GATT回调二、连接和断连三、连接状态回调四、发现服务五、服务适配器六、显示服务七、源码 前言 在上一篇中我们进行扫描设备的处理&#xff0c;本文中进行连接和发现服务的数据处理&#xff0c;运行效果图如下…...

Android 自定义按钮(可滑动、点击)

按钮图片素材 https://download.csdn.net/download/Lan_Se_Tian_Ma/88151085 px 和 dp 转换工具类&#xff08;Java&#xff09; // px 和 dp 转换工具类 public class DensityUtil {/*** 根据手机的分辨率从 dip 的单位 转成为 px(像素)*/public static int dip2px(Conte…...

mac录屏怎么打开?很简单,让我来教你!

mac电脑作为一款广受欢迎的电脑系统&#xff0c;提供了多种方式来满足用户录屏的需求。无论您是要录制教学视频、制作演示文稿&#xff0c;还是记录游戏精彩瞬间&#xff0c;mac电脑都能帮助您实现这些目标。本文将为您介绍两种mac录屏的方法。通过本文的指导&#xff0c;您将能…...

Stable Diffusion AI绘画学习指南【插件安装设置】

插件安装的方式 可用列表方式安装&#xff0c;点开Extensions 选项卡&#xff0c;找到如下图&#xff0c;找到Available选项卡&#xff0c;点load from加载可用插件&#xff0c;在可用插件列表中找到要装的插件按install 按扭按装&#xff0c;安装完后(Apply and restart UI)应…...

APP开发中的性能优化:提升用户满意度的关键

APP开发中的性能优化是需要持续进行的&#xff0c;它不仅能够让用户体验到 APP的使用感受&#xff0c;还能在一定程度上提升用户的满意度&#xff0c;从而提升 APP的粘性和转化率。不过在实际开发中&#xff0c;很多 APP开发公司会存在性能优化上的问题&#xff0c;这就需要了解…...

Golang 切片 常用方法

文章目录 移除指定位置的元素查找元素的位置查找最大最小的元素去重随机打乱排序二维排序sort.Sort 排序 下面的方法省略一些校验&#xff0c;如数组越界等&#xff0c;且都采用泛型(要求go版本 > 1.18) 移除指定位置的元素 package mainimport ("fmt" )func Del…...

【Linux后端服务器开发】poll/epoll多路转接IO服务器

目录 一、poll原理 二、poll实现多路转接IO服务器 三、epoll函数接口 四、epoll的工作原理 五、epoll实现多路转接IO服务器 一、poll原理 poll函数接口 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);// pollfd结构 struct pollfd …...

【设计模式——学习笔记】23种设计模式——命令模式Command(原理讲解+应用场景介绍+案例介绍+Java代码实现)

文章目录 案例引入介绍基础介绍登场角色 案例实现案例一实现 案例二介绍实现拓展 命令模式在JdbcTemplate源码中的应用总结文章说明 案例引入 有一套智能家电&#xff0c;其中有照明灯、风扇、冰箱、洗衣机&#xff0c;这些智能家电来自不同的厂家&#xff0c;我们不想针对每一…...

Rust中的高吞吐量流处理

本篇文章主要介绍了Rust中流处理的概念、方法和优化。作者不仅介绍了流处理的基本概念以及Rust中常用的流处理库&#xff0c;还使用这些库实现了一个流处理程序。 最后&#xff0c;作者介绍了如何通过测量空闲和阻塞时间来优化流处理程序的性能&#xff0c;并将这些内容同步至…...

探索编程世界的宝藏:程序员必掌握的20大算法

文章目录 1 引言2 冒泡排序算法&#xff1a;编程世界的排序魔法 &#x1f9d9;‍♀️&#x1f522;3 选择排序算法&#xff1a;排序世界的精确挑选器 &#x1f3af;&#x1f522;4 插入排序算法&#xff1a;排序世界的巧妙插珠者 ✨&#x1f522;5 快速排序算法&#xff1a;排序…...

Android NFC通信示例

前言 近距离无线通信 (NFC) 是一组近距离无线技术&#xff0c;通常只有在距离不超过 4 厘米时才能启动连接。借助 NFC&#xff0c;您可以在 NFC 标签与 Android 设备之间或者两台 Android 设备之间共享小型负载。 支持 NFC 的 Android 设备同时支持以下三种主要操作模式&…...

2023年08月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年08月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…...

使用Beego和MySQL实现帖子和评论的应用,并进行接口测试(附源码和代码深度剖析)

文章目录 小项目介绍源码分析main.gorouter.gomodels/user.gomodels/Post.gomodels/comment.gocontrollers/post.gocontrollers/comment.go 接口测试测试增加帖子测试查看帖子测试增加评论测试查看评论 小项目介绍 经过对需求的分析&#xff0c;我增加了一些额外的东西&#x…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

stm32G473的flash模式是单bank还是双bank?

今天突然有人stm32G473的flash模式是单bank还是双bank&#xff1f;由于时间太久&#xff0c;我真忘记了。搜搜发现&#xff0c;还真有人和我一样。见下面的链接&#xff1a;https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...

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 …...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...