Lesson 04 模板入门

C++:渴望力量吗,少年?

文章目录

  • 一、泛型编程
    • 1. 引入
    • 2. 函数模板
        • (1)函数模板概念
        • (2)函数模板格式
        • (3)函数模板的原理
        • (4)函数模板的实例化
        • (5)模板参数的匹配原则
    • 3. 类模板
        • (1)类模板的定义格式
        • (2)类模板的实例化


一、泛型编程

1. 引入

  观察下面的代码,是不是发现虽然有函数重载,但是为了实现相同的功能,不得不写成好几个函数,区别仅仅是参数类型不同。

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}
void Swap(double& left, double& right)
{
	double temp = left;
	left = right;
	right = temp;
}
void Swap(char& left, char& right)
{
	char temp = left;
	left = right;
	right = temp;
}

使用函数重载虽然可以实现,但是有以下几个不好的地方:
(1)重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
(2)代码的可维护性比较低,一个出错可能所有的重载均出错
  因此,特意引入了泛型编程的概念,即编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。而模板又分为函数模板和类模板

2. 函数模板

(1)函数模板概念

  函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

(2)函数模板格式

template<typename T1, typename T2, . . . . . . , typename Tn>
返回值类型 函数名(参数列表){}

template<class T>
void Swap(T& left, T& right)//这里要使用&,不然无法交换实参
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	int i = 0, j = 1;
	Swap(i, j);

	double x = 1.1, y = 2.2;
	Swap(x, y);

	return 0;
}

  注意:typename是用来定义模板参数关键字,也可以使用class(切记:不能使用struct代替class)

(3)函数模板的原理

  在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
在这里插入图片描述

(4)函数模板的实例化

  用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
  隐式实例化:让编译器根据实参推演模板参数的实际类型。
  显式实例化:在函数名后的<>中指定模板参数的实际类型。
  如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	cout << Add(1, 2) << endl;//隐式实例化

	//cout << Add(1.1, 2) << endl;//类型不一致时会报错

	//可以使用强制类型转换把两个类型变成一致
	cout << Add((int)1.1, 2) << endl;
	cout << Add(1.1, (double)2) << endl;

	// 显式实例化(直接把两个都统一类型)
	cout << Add<int>(1.1, 2) << endl;
	cout << Add<double>(1.1, 2) << endl;

	return 0;
}
(5)模板参数的匹配原则

  对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。

int Add(int left, int right)//像这里既有Add函数也有Add模板,调用Add函数的时候如果参数类型符合会先使用这个Add函数
{//就相当于编译器偷个懒不去替换模板的T,直接用现成的
    return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
    return left + right;
}

template<class T>
T* func(int n)
{
    return new T[n];
}

int main()
{
	int x = 0, y = 1;
	swap(x, y);//swap其实也是C++已经写好的模板

	double a = 1.1, b = 2.2;
	swap(a, b);

	cout << Add(x, y) << endl;//调用非模板函数

	//主要就是要注意模板的实例化
	cout << Add<int>(x, y) << endl;

	int* ptr = func<int>(10);

	return 0;
}

3. 类模板

(1)类模板的定义格式
template < class T1, class T2, ..., class Tn>
class 类模板名
{
	// 类内成员定义
};
(2)类模板的实例化

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

template<class T>
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		cout << "Stack()" << endl;

		_array = new T[capacity];

		_capacity = capacity;
		_size = 0;
	}

	void Push(const T& data)
	{
		 CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;

		delete[] _array;
		_array = nullptr;
		_size = _capacity = 0;
	}
private:
	T* _array;
	int _capacity;
	int _size;
};
int main()
{
	Stack<int> st1; // int
	Stack<double> st2; // double

	st1.Push(1);
	st1.Push(2);

	st2.Push(1.2);
	st2.Push(1.2);

	return 0;
}

  比如这段代码中Stack< int > 和 Stack< double >才是类型名。

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

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

相关文章

【ATTCK】MITRE Caldera-路径发现插件

CALDERA是一个由python语言编写的红蓝对抗工具&#xff08;攻击模拟工具&#xff09;。它是MITRE公司发起的一个研究项目&#xff0c;该工具的攻击流程是建立在ATT&CK攻击行为模型和知识库之上的&#xff0c;能够较真实地APT攻击行为模式。 通过CALDERA工具&#xff0c;安全…

git基本用法和操作

文章目录 创建版本库方式&#xff1a;Git常用操作命令&#xff1a;远程仓库相关命令分支(branch)操作相关命令版本(tag)操作相关命令子模块(submodule)相关操作命令忽略一些文件、文件夹不提交其他常用命令 创建版本库方式&#xff1a; 创建文件夹 在目录下 右键 Git Bush H…

git rebase 和 git merge的区别?以及你对它们的理解?

文章目录 前言是什么分析区别后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;git操作相关 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;感谢…

卡尔曼滤波器在车流量检测中的应用

目录 1. 作者介绍2. 卡尔曼滤波器2.1 卡尔曼滤波概述2.2 标志性发展2.3 卡尔曼公式理解 3. 车流量检测3.1 背景介绍3.2 实现过程3.2.1 YOLOv3网络模型结构3.2.2 SORT算法3.2.3 基于虚拟线圈法的车辆统计 4. 算法实现4.1 Kalman.py4.2 完整代码4.3 结果展示 1. 作者介绍 吴思雨…

【STM32】IIC(Inter Integrated Cirruit--集成电路总线)

【单片机】14-I2C通信之EEPROM-CSDN博客 一、IIC总线协议介绍 1.IIC简介 同步&#xff08;有时钟频率&#xff09;&#xff0c;半双工&#xff08;同一个时间只能接收或者发送&#xff09;&#xff0c;串行&#xff08;一个字节一个字节传输&#xff09;&#xff0c;高位读取…

卷积神经网络(VGG-16)海贼王人物识别

文章目录 前期工作1. 设置GPU&#xff08;如果使用的是CPU可以忽略这步&#xff09;我的环境&#xff1a; 2. 导入数据3. 查看数据 二、数据预处理1. 加载数据2. 可视化数据3. 再次检查数据4. 配置数据集5. 归一化 三、构建VGG-16网络1. 官方模型&#xff08;已打包好&#xff…

小迪笔记(1)——操作系统文件下载反弹SHELL防火墙绕过

名词解释 POC&#xff1a;验证漏洞存在的代码&#xff1b; EXP&#xff1a;利用漏洞的代码&#xff1b; payload&#xff1a;漏洞利用载荷&#xff0c; shellcode&#xff1a;漏洞代码&#xff0c; webshell&#xff1a;特指网站后门&#xff1b; 木马&#xff1a;强调控制…

MVSNet论文笔记

MVSNet论文笔记 摘要1 引言2 相关基础2.1 多视图立体视觉重建&#xff08;MVS Reconstruction&#xff09;2.2 基于学习的立体视觉&#xff08;Learned Stereo&#xff09;2.3 基于学习的多视图的立体视觉&#xff08;Learned MVS&#xff09; Yao, Y., Luo, Z., Li, S., Fang,…

Linux 零拷贝splice函数

Linux splice 函数简介 splice 是 Linux 系统中用于在两个文件描述符之间移动数据的系统调用。它的主要作用是在两个文件描述符之间传输数据&#xff0c;而无需在用户空间进行数据拷贝。也是零拷贝操作. 函数原型 #include <fcntl.h> ssize_t splice(int fd_in, loff_…

『Spring Boot Actuator Spring Boot Admin』 实现应用监控管理

前言 本文将会使用 Spring Boot Actuator 组件实现应用监视和管理&#xff0c;同时结合 Spring Boot Admin 对 Actuator 中的信息进行界面化展示&#xff0c;监控应用的健康状况&#xff0c;提供实时警报功能 Spring Boot Actuator 简介 官方文档&#xff1a;Production-rea…

【Java 进阶篇】JQuery 事件绑定:`on` 与 `off` 的奇妙舞曲

在前端开发的舞台上&#xff0c;用户与页面的互动是一场精彩的表演。而 JQuery&#xff0c;作为 JavaScript 的一种封装库&#xff0c;为这场表演提供了更为便捷和优雅的事件绑定方式。其中&#xff0c;on 和 off 两位主角&#xff0c;正是这场奇妙舞曲中的核心演员。在这篇博客…

【C++】一文全解C++中的异常:标准库异常体系&自定义异常体系(含代码演示)

前言 大家好吖&#xff0c;欢迎来到 YY 滴C系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 目录 一.C语言传统的处理错误的方式二.C异常…

Unity中Shader法线贴图(上)

文章目录 前言一、法线纹理的作用二、为什么法线贴图长这样&#xff1f;&#xff08;蓝色&#xff09;三、法线贴图能使纹理采样时&#xff0c;进行偏移采样四、在Shader中使用法线贴图1、在属性面板定义一个变量来接收法线贴图2、在使用前声明 _NormalTex3、在片元着色器中&am…

SQLite 安装和 Java 使用教程

SQLite是一个C语言库&#xff0c;它实现了一个小型、快速、自包含、高可靠性、功能齐全的SQL数据库引擎。SQLite是世界上使用最多的数据库引擎。SQLite内置于所有手机和大多数计算机中&#xff0c;并捆绑在人们每天使用的无数其他应用程序中。 SQLite文件格式稳定、跨平台、向…

系列三、GC垃圾回收算法和垃圾收集器的关系?分别是什么请你谈谈

一、关系 GC算法&#xff08;引用计数法、复制算法、标记清除算法、标记整理算法&#xff09;是方法论&#xff0c;垃圾收集器是算法的落地实现。 二、4种主要垃圾收集器 4.1、串行垃圾收集器&#xff08;Serial&#xff09; 它为单线程环境设计&#xff0c;并且只使用一个线程…

Java --- JVM之垃圾回收相关算法

目录 一、垃圾标记算法 1.1、垃圾标记阶段&#xff1a;对象存活判断 1.2、引用计数算法 1.3、可达性分析算法 1.4、GC Roots 二、对象的finalization机制 2.1、生存还是死亡&#xff1f; 三、查看GC Roots 3.1、使用MAT查看 四、使用JProfiler分析OOM 五、清除阶段算…

李宏毅2023机器学习作业HW05解析和代码分享

ML2023Spring - HW5 相关信息&#xff1a; 课程主页 课程视频 Sample code HW05 视频 HW05 PDF 个人完整代码分享: GitHub | Gitee | GitCode 运行日志记录: wandb P.S. HW05/06 是在 Judgeboi 上提交的&#xff0c;完全遵循 hint 就可以达到预期效果。 因为无法在 Judgeboi 上…

git常用命令和参数有哪些?【git看这一篇就够了】

文章目录 前言常用命令有哪些git速查表奉上常用参数后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;git操作相关 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出…

MIB 6.S081 System calls(1)using gdb

难度:easy In many cases, print statements will be sufficient to debug your kernel, but sometimes being able to single step through some assembly code or inspecting the variables on the stack is helpful. To learn more about how to run GDB and the common iss…

每天一道算法题(六)——返回一组数字中所有和为 0 且不重复的三元组

文章目录 前言1、问题2、示例3、解决方法4、效果5、注意点 前言 注意&#xff1a;答案中不可以包含重复的三元组。 1、问题 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] n…