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

c++----初识模板

        大家好,这篇博客想与大家分享一些我们c++中比较好用的知识点。模板。首先咧,我们都知道模板嘛,就是以前人的经验总结出来的知识。方便我们使用。这里的模板也是一样的。当我们学习过后,对于一些在c中的自定义函数,我们在c++中使用就会很方便了。但是因为我们这里只是初识。因为我们现在学识尚浅,太过高深的话,就一点过载了,所以我们这里就暂时交给大家如何辨认和使用简单的模板。

泛型模板

        首先我们可以从我们的标题看到我们这一小节讲的是广泛的模板,就是使用的范围相对较广,但是只是较广并不是通用。我们这里就以我们以前在c中常使用的一个自定义函数swap来说,但其实我们在c中就说过,我们学习了c++就不需要再自己写了,也不需要写头文件,因为我们c++中swap很有可能会被间接包含所以我们通常是直接使用,这里我们为了方便教学就以这个为例。

      大家都知道,我们平常的swap是确定了参数类型的,不能不同参数进行交换,就像我们下面的图片:

        在我们c的时候为了应对不同的参数类型所以我们需要写多个参数版本。使用函数重载虽然可以实现,但是有一下几个不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数

2. 代码的可维护性比较低,一个出错可能所有的重载均出错
那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 呢?
         如果在 C++ 中,也能够存在这样一个 模具 ,通过给这个模具中 填充不同材料 ( 类型 ) ,来 获得不同 材料的铸件 ( 即生成具体类型的代码) ,那将会节省许多头发。巧的是前人早已将树栽好,我们只 需在此乘凉。 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

函数模板

        对于我们的函数模板,它代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。已就是说。我们的c++模板不会受到参数类型的限制,只要我们写的参数个数正确就可以了。虽然我这里很简单说,只需要确定参数个数就可以了。但其实也真的很简单。

        那么我们就来看看函数的模板是如何书写的。首先我们要先写一个:template<typename T1, typename T2,......,typename Tn> 。大体是这样的但是个数就是自己确定。是不是很简单啊。那么我们来写一个swap模板,并且看看如何使用的:         上面的图片,大家可以看到在使用模板前,我们先写了一个声明。然后写的我们模板。这里大家是否有留意到我们声明的时候只写了一个参数类型啊,就是我们这里template<typename T>中只有一个参数。这就表明了我们这里的模板参数类型只能有一种参数类型。

        我想大家看了上面的那句话应该会想到一个疑问吧,这就是啥意思啊。上面写了一个参数,就代表只有一种参数类型了。那是不是我上面多写几个,那么我就可以在模板中使用多种参数类型了呀。但确实是这样的,我们可以在声明的时候多些几种,那么模板就可以多使用几种,那我们来看看例子:

       这里我们是没有报错的,这是因为我们在上面写了两个声明的类型,所以我们在模板中可以使用两种参数变量,虽然结果可能不尽人意但是我们的却还是确定了一点。我们如果在前面写多个参数那么下面的模板就可以使用多种参数类型。

:括号里面的声明是只能写typename还可以写成clsaa,但是大家不要多想以为class可以写,那么struct也可以写。这就错了。表明参数类型能个数的就只有这两种表达。没有其他的了

函数模板的原理,对于我们学习的人来说,主打一个刨根问底。那么我们对于这个函数模板多多少少也是需要了解的。但其实大家如果看到这里了,就应该对函数模板的原理也差不多了吧。毕竟我们的标题就写的很清楚了啊。模板嘛。函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器我感觉有点像一个没有灵魂的人,只要有灵魂进入这幅躯体,那么这幅躯体就可以凭借这个灵魂带来的思想来完成自己的心愿。就像可以被人随意控制的木偶一样。大家可以看一下下面的图片:       这里就有点像我上面写的那个灵魂一样。只要想用就进入这幅空壳,凭借这幅躯体就可以做出其他的事情。但如果稍微官方一点的话就是:在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。这个大家可以复杂理解,也可以简单思考,反正我觉得稍微知道是个啥意思就可以了,如果深入太多的话,就可能有点吃不消了。

函数模板的实例化:大家可能看到这个小标题会有点懵。啊。实例化,什么个意思怎么会用在这里啊。大家别急。用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化这里我们知道了示例化有两种。一个是显示一个是隐式。那么我们就来先看看显示实例化:

       我们这里的Add只写了一种参数个数,如果按我们前面说的话,不是只能有一种参数类型吗?这里怎么有两种啊。但大家应该也看到了,在我们调用的前面写了一个<int>。这就好比我们在c中写过的强制类型转换。只是我们写的这里是将这两个全都转换成int,int转换为int不变嘛,但是我double可以转换为it强制类型转换,当然也可以这样写:

      反正如果我们写的参数个数类型只写了一个的话,我们可以将我们不同的参数类型进行转换,然后使用。还有对于隐式实例化的话就是比较简单的,其实就是我们普通的使用方法也是使用转换,就是我们相同的参数类型:

       这就是我们说的隐式类实例化,就是我们平常的使用方法,但是对于我们如果想用两种不同的参数类型,并且我们的参数类型个数只有一个的话,就只能强转或者我们刚刚的显示实例化。 

模板参数的匹配原则 :不知道大家是否会有一个想法,就是因为我们c++可以重载函数,如果我们创建一个模板,然后再创建一个重载函数,并且它们的参数是一样的,名字是一样的。那如果我调用的话会调用哪一个呢?对于这个大家其实可以有一个很简单的想法。例如编译器是一个人的话,我其实个人觉得人都是想着少做一点是一点。反正钱拿的是一样的。那为什么我不躺平一点呢?以现在的情况为例,如果有一个自定义函数的参数类型与模板函数是一样的,那么如果调用的话肯定是直接调用使用人写的那个,因为如果使用模板函数的话,编译器还会自己动一下,我干嘛还要自己动呢?你反正你已经写了,是吧?

       这里我是简单的用f11调试给大家看的,虽然可能大家会怀疑,但确实是这样,如果当一个非模板函数与模板函数同时调用的话,会先调用非模板函数,大家知道就可以了。模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。

类模板

       大家也看到了上面我们所有的文章都是依照函数来写的,但是我们c++呢肯定不只有函数,我们前面学的最多的就是类了,我们那也是有模板的。其实对于类的模板格式与我们的函数模板格式相差无几。区别就是我们类的写法,我们自定义函数的写法是不一样的。那么我们看一下类模板的定义格式是什么样的?

类模板的定义格式:

template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};

        我们前面说过类模板的第一个是与我们的函数模板格式差不多,只是融汇了自己各自的特点。也许大家会想类模板有什么作用呢?

  1. 一些类主要用于存储和组织数据元素
  2. 类中数据组织的方式和数据元素的具体类型无关
  3. 如:数组类,链表类,Stack类,Queue类,等

C++中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。

实现类模板:

  1. 以相同的方式处理不同的类型
  2. 在类声明前使用template进行标识
  3. < typename T >用于说明类中使用的泛指类型T 

       这里我们是以我们C中使用过的扩容。大家可能很难看出来,但其实我们不看这个,我们主要是看我们的模板是如何使用的。后面大家加油以此为蓝本来写,也许大家会问啊,关于模板函数我们知道的少怎么分析这个类模板函数列:

1. 与函数模板不同,只能显示指定具体类型,无法自动推导。
2. 声明的泛指类型T 可以出现在类模板的任意地方
3. 编译器对类模板的处理方式和函数模板相同
a) 从类模板通过具体类型产生不同的类
b) 在声明的地方对类模板代码本身进行编译
c) 在使用的地方对参数替换后的代码进行编译

        大家可以多理解上面分析。并且大家需要知道的一个不能忘的点就是我们类模板的头文件与源文件不能分开。具体是什么原因。在下暂时还不知道。但是我尝试过分开确实会报错的,所以大家现在知道不能分开就可以了。

类模板的实例化: 类模板实例化与函数模板实例化不同, 类模板实例化需要在类模板名字后跟 <> ,然后将实例化的 类型放在 <> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double

总结

       好的,上面这些就是本篇博客想与大家分享的模板的一些相关的基础知识,我知道可能大家会很多的不了解,尤其是类模板的。相较于函数模板的话,类模板确实要有更多的知识点,但是大家不要害怕,我们可以多稍微多理解几遍,看几遍就可以了解的更多了。模板嘛,毕竟是我们c++中最好用的一个东西啊,因为相较于c中它没有我们c++有就更好用了。好,鄙人在这里祝各位前程似锦!!!

相关文章:

c++----初识模板

大家好&#xff0c;这篇博客想与大家分享一些我们c中比较好用的知识点。模板。首先咧&#xff0c;我们都知道模板嘛&#xff0c;就是以前人的经验总结出来的知识。方便我们使用。这里的模板也是一样的。当我们学习过后&#xff0c;对于一些在c中的自定义函数&#xff0c;我们在…...

SpringBoot3热部署

引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional> </dependency> 默认就是,无需配置 可以了…...

J. 二进制与、平方和

https://codeforces.com/gym/104095/problem/J 分析操作一 1&00 ,0&10&#xff0c;ai<qmi(2,24),说明每个数最多操作25次 维护区间或和&#xff0c;orsum & x orsum 就不用递归下去了 势能线段树code // Problem: J. 二进制与、平方和 // Contest: Codeforc…...

LVS中NAT模式和DR模式实战讲解

1DR模式 DR&#xff1a;Direct Routing&#xff0c;直接路由&#xff0c;LVS默认模式,应用最广泛,通过为请求报文重新封装一个MAC首部进行 转发&#xff0c;源MAC是DIP所在的接口的MAC&#xff0c;目标MAC是某挑选出的RS的RIP所在接口的MAC地址&#xff1b;源 IP/PORT&#xf…...

写给小白程序员的一封信

文章目录 1.编程小白如何成为大神&#xff1f;大学新生的最佳入门攻略2.程序员的练级攻略3.编程语言的选择4.熟悉Linux5.学会git6.知道在哪寻求帮助7.多结交朋友8.参加开源项目9.坚持下去 1.编程小白如何成为大神&#xff1f;大学新生的最佳入门攻略 编程已成为当代大学生的必…...

Leaf分布式ID

文章目录 系统对Id号的要求UUIDsnowflakeLeafLeaf-snowflakeLeaf-segmentMySQL自增主键segment双buffer 系统对Id号的要求 1、业务 1&#xff09;全局唯一性&#xff1a;不能出现重复的ID号&#xff0c;既然是唯一标识&#xff0c;这是最基本的要求 2&#xff09;趋势递增&a…...

Starrocks解析json数组

json数据 [{"spec": "70g/支","unit": "支","skuId": "1707823848651276346","amount": 6,"weight": 70,"spuName": "伊利 甄稀 苦咖啡味雪糕 流心冰淇淋 70g/支",&quo…...

安卓基本布局(下)

TableLayout 常用属性描述collapseColumns设置需要被隐藏的列的列号。shrinkColumns设置允许被伸缩的列的列号。stretchColumns设置允许被拉伸的列的列号。 <TableLayout xmlns:android"http://schemas.android.com/apk/res/android"android:id"id/TableL…...

Python中使用正则表达式

摘要&#xff1a; 正则表达式&#xff0c;又称为规则表达式&#xff0c;它不是某种编程语言所特有的&#xff0c;而是计算机科学的一个概念&#xff0c;通常被用来检索和替换某些规则的文本。 一.正则表达式的语法 ①行定位符 行定位符就是用来描述字符串的边界。"^&qu…...

三大口诀不一样的代码,小小的制表符和换行符玩的溜呀

# 小案例&#xff0c;打印输出加法口诀 for i in range(1,10):for j in range(1,10):if j>i:breakprint(f"{j}{i}{ji}".strip(),end\t)print() print(\n) for i in range(1,10):for j in range(1,10):if j>i:breakprint(f"{j}x{i}{j*i}",end\t)print…...

[qt] 线程等待与唤醒

对于生产者与消费者的数据处理的另一种好的解决方法是使用QWaitCondition类,允许线程在一定的条件下唤醒其他多个线程来共同处理。 一 定义公共变量 DataSize: 生产者生产数据的大小BufferSize: 也就是这个缓冲区的大小,每个单元是一个int&#xff0c;也有可能是一个链表,结构…...

Springboot 实现 Modbus Rtu 协议接入物联网设备

Modbus RTU 技术教程 引言 Modbus是一种开放标准的通信协议,它最初由Modicon(现施耐德电气)在1979年发布,旨在让可编程逻辑控制器(PLC)之间能够进行通信。随着时间的发展,Modbus已经成为工业自动化领域中最常用的通信协议之一,尤其适用于连接工业电子设备。本文将详细…...

鸿蒙笔记--装饰器

这一节主要了解一下鸿蒙里的装饰器,装饰器是一种特殊的语法结构&#xff0c;用于装饰类、结构体、方法以及变量; 1 Component在鸿蒙&#xff08;HarmonyOS&#xff09;开发中扮演着重要角色&#xff0c;主要用于定义可重用的UI组件,主要作用:1)组件化&#xff1a;Component装饰…...

不同环境下RabbitMQ的安装-3 操作RabbitMQ

前面两篇从不同环境下RabbitMQ的安装-1 为什么要使用消息服务 到同环境下RabbitMQ的安装-2 ARM架构、X86架构、Window系统环境下安装RabbitMQ介绍了关于如何在ARM架构、X86架构和Window系统下如何安装&#xff0c;各位小伙伴可以根据自己的实际开发场景参考安装。 到本篇是一些…...

postgregSQL配置vector插件

1.下载vector 下载vector&#xff1a;https://pgxn.org/dist/vector/0.5.1/ 放在&#xff1a;C:\Program Files\PostgreSQL\vector-0.5.1 2.安装Visual Studio 2022 下载&#xff1a;https://visualstudio.microsoft.com/zh-hans/downloads/ 安装Visual Studio是为了C编译环…...

PUMA论文阅读

PUMA: Efficient Continual Graph Learning with Graph Condensation PUMA&#xff1a;通过图压缩进行高效的连续图学习 ABSTRACT 在处理流图时&#xff0c;现有的图表示学习模型会遇到灾难性的遗忘问题&#xff0c;当使用新传入的图进行学习时&#xff0c;先前学习的这些模…...

算法学习day31(动态规划)

一、比特位计数 给你一个整数 n &#xff0c;对于 0 < i < n 中的每个 i &#xff0c;计算其二进制表示中 1 的个数 &#xff0c;返回一个长度为 n 1 的数组 ans 作为答案。 输入&#xff1a;n 2 输出&#xff1a;[0,1,1] 解释&#xff1a;0 --> 0 1 --> 1 2 -…...

嵌入式学Day25---Linux软件编程---线程间通信

目录 ​编辑 一、线程的分离属性 1.1.什么是分离属性 1.2.分离属性相关函数接口 1.初始化线程属性-pthread_attr_init() 2.销毁线程属性-pthread_attr_destory() 3.设置线程属性-pthread_setdetachstate() 1.3.注意 二、互斥锁 2.1.资源 2.2.互斥锁 1.什么是互斥锁 2.互…...

【实现100个unity特效之17】在unity中使用shader和ShaderGraph分别实现模糊特定层,高斯模糊效果

最终效果 Unity通过Shader来模糊场景画面 参考&#xff1a;【游戏开发小技】Unity通过UI全屏图来模糊场景画面&#xff08;Shader | 模糊 | 滤镜 | Blur&#xff09; ShaderGraph实现图片的高斯模糊 参考&#xff1a;【游戏开发实战】Unity ShaderGraph实现图片的高斯模糊效…...

Unity补完计划 之 SpriteEditer Multiple

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正 1. SpriteEditer Multiple Automatic slicing - Unity 手册 这是用于裁剪图集的模式 应用之后精灵编辑器会看到Slice亮…...

11.RV1126-ROCKX项目 API和人脸检测画框

一.ROCKX的API 1.ROCKX的作用 ROCKX的AI组件可以快速搭建 AI的应用&#xff0c;这些应用可以是车牌识别、人脸识别、目标识别&#xff0c;人体骨骼识别等等。主要用于各种检测识别。例如下图&#xff1a; 2.ROCKX人脸识别的API rockx_ret_t rockx_create(rockx_handle_t *han…...

Next.js+prisma开发一

1.初始化Next.js项目 #按版本安装 npx create-next-app13.4.5 如果最新版本 执行&#xff1a;npx create-next-applatest2. 安装Prima和客户端 npm install prisma --save-dev npm install prisma/client3.初始化Prisma&#xff0c;以SQLit举例 # 初始化 Prisma 并配置 SQLi…...

✅ 常用 Java HTTP 客户端汇总及使用示例

在 Java 开发中&#xff0c;HTTP 客户端是与服务端交互的关键组件。随着技术发展&#xff0c;出现了多种 HTTP 客户端库&#xff0c;本文汇总了常用的 Java HTTP 客户端&#xff0c;介绍其特点、适用场景&#xff0c;并附上简单使用示例&#xff0c;方便开发者快速选择和上手。…...

基于本地LLM与MCP架构构建AI智能体全指南

一、AI智能体开发的新范式 随着人工智能技术的快速演进&#xff0c;AI智能体&#xff08;AI Agents&#xff09;正成为连接技术创新与实际应用的核心载体。从智能家居的温控系统到复杂的金融风控决策&#xff0c;AI智能体通过感知环境并执行目标导向的行为&#xff0c;正在重塑…...

聊一聊 .NET在Linux下的IO多路复用select和epoll

一&#xff1a;背景 1. 讲故事 在windows平台上&#xff0c;相信很多人都知道.NET异步机制是借助了Windows自带的 IO完成端口 实现的异步交互&#xff0c;那在 Linux 下.NET 又是怎么玩的呢&#xff1f;主要还是传统的 select&#xff0c;poll&#xff0c;epoll 的IO多路复用…...

React Hooks 基础指南

React Hooks 是 React 16.8 引入的重要特性&#xff0c;它允许开发者在函数组件中使用状态和其他 React 特性。本文将详细介绍 6 个最常用的 React Hooks。 1. useState useState 是最常用的 Hook&#xff0c;用于在函数组件中添加 state。 import React, { useState } from…...

打造高效多模态RAG系统:原理与评测方法详解

引言 随着信息检索与生成式AI的深度融合&#xff0c;检索增强生成&#xff08;RAG, Retrieval-Augmented Generation&#xff09; 已成为AI领域的重要技术方向。传统RAG系统主要依赖文本数据&#xff0c;但真实世界中的信息往往包含图像、表格等多模态内容。多模态RAG&#xf…...

C语言 标准I/O函数全面指南

C标准I/O函数全面指南 本指南详细介绍了C语言中用于文件操作的标准输入/输出函数&#xff0c;包括单字符I/O、字符串I/O、格式化I/O、块I/O以及文件光标操作。每个部分包含函数定义、使用说明和实用示例&#xff0c;适合学习、复习以及博客发布。内容采用清晰的Markdown格式&a…...

Elasticsearch中的地理空间(Geo)数据类型介绍

在Elasticsearch中,地理空间(Geo)数据类型用于存储和处理与地理位置相关的数据,支持基于地理坐标的查询、过滤和分析。这类数据类型允许用户在分布式环境中高效地处理地理空间相关的搜索、聚合和可视化需求,广泛应用于地图应用、物流追踪、位置服务(LBS)等场景。 一、核…...

OpenCV CUDA模块特征检测------角点检测的接口createMinEigenValCorner()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 该函数创建一个 基于最小特征值&#xff08;Minimum Eigenvalue&#xff09;的角点响应计算对象&#xff0c;这是另一种经典的角点检测方法&…...