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;
}

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/57981.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文读透时区和时间戳以及基于Java的操作

重要概念 1. UTC 和 UTC8 UTC 是世界标准时间&#xff0c; UTC8 是东八区标准时间&#xff0c;中国就属于东八区&#xff0c; 也就是北京时间。 8 就是加8个小时。 时区的划分图示如下&#xff1a; 也就是说&#xff1a; 假如现在是UTC时间是 2023-08-08 01:00:00 &#xff0…

MySQL数据库——多表操作

文章目录 前言多表关系一对一关系一对多/多对一关系多对多关系 外键约束创建外键约束插入数据删除带有外键约束的表的数据删除外键约束 多表联合查询数据准备交叉连接查询内连接查询外连接查询左外连接查询右外连接查询满外连接查询 子查询子查询关键字ALL 关键字ANY 和 SOME 关…

k8s kubeadm命令升级集群 从1.17升级到1.18

k8s kubeadm命令升级集群 从1.17升级到1.18 大纲 注意事项master节点执行升级命令master节点和node节点执行命令 注意事项 目标当前线上k8s集群版本是k8s1.17 想把k8s升级到1.18。注意k8s不能跨版本升级例如k8s1.17不能直接升级到k8s1.19&#xff0c;需要先升级到1.18才后向…

【使用 DSP 滤波器加速速度和位移】使用信号处理算法过滤加速度数据并将其转换为速度和位移研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

dubbo的高可用

1、zookeeper宕机与dubbo直连 现象&#xff1a;zookeeper注册中心宕机&#xff0c;还可以消费dubbo暴露的服务。 原因&#xff1a; 健壮性 &#xff08;1&#xff09;监控中心宕掉不影响使用&#xff0c;只是丢失部分采样数据. &#xff08;2&#xff09;数据库宕掉后&#x…

springboot访问请求404的原因

是记录&#xff0c;可能出现错误 可能出现的原因 1.你请求的URL路径不对,比如说你请求的路径是/usr/list,GET方法,但是你UserController上面的RequestMapping是这个样子:RequestMapping(“user”)&#xff0c;有可能哈 2.前端的请求时GET方法&#xff0c;后端对应的处理函数的方…

C++ 指针数组

如果一个数组的每个元素都是指针变量&#xff0c;这个数组就是指针数组。指针数组的每个元素都必须是同一类型的指针。 1.一维指针数组 声明一维指针数组的语法形式&#xff1a; 数据类型*数组名[下标表达式];下标表达式指出数组元素的个数&#xff0c;数据类型确定每个元素…

Kafka3.0.0版本——生产者如何提高吞吐量

目录 一、生产者提高吞吐量参数设置二、产者提高吞吐量代码示例 一、生产者提高吞吐量参数设置 batch.size&#xff1a;设置批次大小&#xff0c;默认16klinger.ms&#xff1a;设置等待时间&#xff0c;修改为5-100msbuffer.memory&#xff1a;设置缓冲区大小&#xff0c; 默认…

信号槽中的函数重载

信号槽中的函数重载 QT4的方式QT5的方式函数指针重载函数QT5信号函数重载解决方案 总结 QT4的方式 Qt4中声明槽函数必须要使用 slots 关键字, 不能省略。 信号函数&#xff1a; 槽函数&#xff1a; mainwondow: cpp文件&#xff1a; #include "mainwindow.h"…

快速部署外卖系统:利用现代工具简化开发流程

在竞争激烈的外卖市场中&#xff0c;快速部署高效稳定的外卖系统是餐饮企业成功的关键之一。本文将介绍如何利用现代工具简化外卖系统的开发流程&#xff0c;并附带代码示例&#xff0c;帮助开发者快速搭建功能完备、用户友好的外卖平台。 1. 简介 在外卖业务快速增长的背景…

使用express搭建后端服务

目录 1 创建工程目录2 初始化3 安装express依赖4 启动服务5 访问服务总结 上一篇我们利用TDesign搭建了前端服务&#xff0c;现在的开发讲究一个前后端分离&#xff0c;后端的话需要单独搭建服务。后端服务的技术栈还挺多&#xff0c;有java、php、python、nodejs等。在众多的技…

稍微深度踩坑haystack + whoosh + jieba

说到django的全文检索&#xff0c;网上基本推荐的都是 haystack whoosh jieba 的方案。 由于我的需求对搜索时间敏感度较低&#xff0c;但是要求不能有数据的错漏。 但是没有调试的情况下&#xff0c;搜索质量真的很差&#xff0c;搞得我都想直接用Like搜索数据库算了。 但是…

排序八卦炉之冒泡、快排

文章目录 1.冒泡排序1.1代码实现1.2复杂度 2.快速排序2.1人物及思想介绍【源于百度】2.2hoare【霍尔】版本1.初识代码2.代码分析3.思其因果 3.相关博客 1.冒泡排序 1.1代码实现 //插入排序 O(N)~O(N^2) //冒泡排序 O(N)~O(N^2) //当数据有序 二者均为O(N) //当数据接近有序或…

什么是 webpack?

Webpack 介绍 什么是 webpack&#xff1f; :::tip 官方描述 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具。当 webpack 处理应用程序时&#xff0c;它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)&#xff0c;然后将你项目中所需的每一个…

第四章 数据库安全性

问题的提出 &#xff08;1&#xff09;数据库的一大特点是数据可以共享 &#xff08;2&#xff09;数据共享必然带来数据库的安全性问题 &#xff08;3&#xff09;数据库系统中的数据共享不能是无条件的共享 这就引发了数据库安全性问题 1.数据库安全性概述 数据库的安全性…

MySQL日志——查询日志

1.查询日志 show variables like %general%;修改mysql的配置文件 /etc/my.cnf文件&#xff0c;添加如下内容&#xff1a; #该选项用来开启查询日志&#xff0c;可选值&#xff1a;0或者1&#xff1b;0代表关闭&#xff0c;1代表开启 general_log1 #设置日志的文件名&#xff0…

C# Blazor 学习笔记(8):row/col布局开发

文章目录 前言相关文章代码row和col组件B_rowB_col结构 使用 前言 可能是我用的element ui和 uView这种第三方组件用的太多了。我上来就希望能使用这些组件。但是目前Blazor目前的生态其实并不完善&#xff0c;所以很多组件要我们自己写。 我们对组件的要求是 我们在组件化一共…

纯粹即刻,畅享音乐搜索的轻松体验

纯粹即刻&#xff0c;畅享音乐搜索的轻松体验 在当今快节奏的生活中&#xff0c;我们常常渴望一种简单而便捷的方式来探索和享受音乐。现在&#xff0c;你可以纯粹即刻地畅享音乐搜索的轻松体验。无论你是寻找热门歌曲还是探索不同风格的音乐&#xff0c;这款应用将为你带来随…

地址空间细致入微+深入了解页表

目录 地址空间保存了什么&#xff1f; 页表到底是怎么存储的 我们都知道&#xff0c;我们进程看到的空间其实是虚拟内存&#xff0c;真正的内存是需要页表的映射才能找到真正的物理内存&#xff0c;那么我我们有两个问题的引出那么进程地址空间是保存了什么呢&#xff1f;页表…

Maven项目解决cannot resolve plugin maven-deploy-plugin:2.7

导入maven项目后&#xff0c;编辑的时候提示一些插件加载失败&#xff01;大概率是你的网络有问题&#xff0c;插件下载失败。 如下图&#xff1a;&#xff08;网络突然好了&#xff0c;我想截图但是没有复现&#xff0c;用网上找到的截图代替&#xff0c;明白意思就行&#x…