当前位置: 首页 > 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…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

Day131 | 灵神 | 回溯算法 | 子集型 子集

Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 笔者写过很多次这道题了&#xff0c;不想写题解了&#xff0c;大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

Golang——6、指针和结构体

指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

快速排序算法改进:随机快排-荷兰国旗划分详解

随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

机器学习的数学基础:线性模型

线性模型 线性模型的基本形式为&#xff1a; f ( x ) ω T x b f\left(\boldsymbol{x}\right)\boldsymbol{\omega}^\text{T}\boldsymbol{x}b f(x)ωTxb 回归问题 利用最小二乘法&#xff0c;得到 ω \boldsymbol{\omega} ω和 b b b的参数估计$ \boldsymbol{\hat{\omega}}…...