Lesson 04 模板入门

news2025/3/12 13:13:48

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 >才是类型名。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

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

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

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

阿坤老师的独特瓷器(Java详解)

一、题目描述 示例&#xff1a; 输入&#xff1a; 5 3 4 5 6 2 5 3 7 6 5 输出&#xff1a; 3 二、题解 思路分析&#xff1a; 题目要求我们计算出“独特瓷器”的个数&#xff0c;而“独特瓷器”是指对于瓷器A&#xff0c;没有另一个瓷器B&#xff0c;直径和高度都大于A。则…

系列三、双亲委派 沙箱安全 机制

一、概述 当一个类收到了类加载的请求&#xff0c;它首先不会尝试自己去加载这个类&#xff0c;而是把这个请求委派给父类去完成&#xff0c;每一层的类加载器都是如此&#xff0c;因此所有的请求最终都应该传送到启动类加载器中&#xff0c;只有当父类加载器反馈自己无法完成…

算法通关村——数字中的统计、溢出、进制转换处理模板

数字与数学基础问题 1、数字统计 1.1、符号统计 LeetCode1822. 给定一个数组&#xff0c;求所有元素的乘积的符号&#xff0c;如果最终答案是负的返回-1&#xff0c;如果最终答案是正的返回1&#xff0c;如果答案是0返回0. 这题其实只用看数组中0和负数的个数就好了&#x…

基于卡尔曼滤波实现行人目标跟踪

目录 1. 作者介绍2. 目标跟踪算法介绍2.1 目标跟踪背景2.2 目标跟踪任务分类2.3 目标跟踪遇到的问题2.4 目标跟踪方法 3. 卡尔曼滤波的目标跟踪算法介绍3.1 所用数据视频说明3.2 卡尔曼滤波3.3 单目标跟踪算法3.3.1 IOU匹配算法3.3.2 卡尔曼滤波的使用方法 3.4 多目标跟踪算法 …

【顺序表的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 数据结构相关概念 1、什么是数据结构 2、为什么需要数据结构&#xff1f; 2、顺序表 1、顺序表的概念及结构 1.1 线性表 2、顺序表分类 3、动态顺序表的实现 总…

高效管理文件:如何通过文件数量归类提高工作效率

在日常生活和工作中&#xff0c;需要处理大量的文件和资料。然而&#xff0c;如果这些文件没有得到妥善的管理&#xff0c;就会使得我们花费大量的时间和精力去寻找和整理它们。对于大量文件&#xff0c;按照数量归类可以使得文件管理更加有序和规范。根据文件的数量建立相应的…

中国电影票房排行数据爬取及分析可视化

大家好&#xff0c;我是带我去滑雪&#xff01; 对中国电影票房排行数据的爬取和分析可视化具有多方面的用处&#xff1a;例如了解电影市场的历史趋势&#xff0c;包括不同类型电影的受欢迎程度、票房的季节性波动。识别观众对于不同类型电影的偏好&#xff0c;为电影制片方提供…

Linux下快速确定目标服务器支持哪些协议和密码套件

实现原理是利用TLS协议的特点和握手过程来进行测试和解析响应来确定目标服务器支持哪些TLS协议和密码套件。 在TLS握手过程中&#xff0c;客户端和服务器会协商并使用相同的TLS协议版本和密码套件来进行通信。通过发送特定的握手请求并分析响应&#xff0c;可以确定目标服务器…

Linux 零拷贝splice函数

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

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

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

数电实验-----实现74LS139芯片扩展为3-8译码器以及应用(Quartus II )

目录 一、74LS139芯片介绍 芯片管脚 芯片功能表 二、2-4译码器扩展为3-8译码器 1.扩展原理 2.电路图连接 3.仿真结果 三、3-8译码器的应用&#xff08;基于74ls139芯片&#xff09; 1.三变量表决器 2.奇偶校验电路 一、74LS139芯片介绍 74LS139芯片是属于2-4译码器…

设计模式-组合模式-笔记

“数据结构”模式 常常有一些组件在内部具有特定的数据结构&#xff0c;如果让客户程序依赖这些特定数据结构&#xff0c;将极大地破坏组件的复用。这时候&#xff0c;将这些特定数据结构封装在内部&#xff0c;在外部提供统一的接口&#xff0c;来实现与特定数据结构无关的访…

【libGDX】使用ShapeRenderer绘制几何图形

1 ShapeRenderer 简介 ShapeRenderer 是 libGDX 中用于绘制基本形状的工具之一。它可以绘制点、线、矩形、多边形、圆形、椭圆形、扇形、立方体、圆锥体等几何图形。这对于在游戏或图形应用程序中绘制简单的形状是很有用的。 ShapeRenderer 的主要方法如下&#xff1a; 1&…

10_6 input输入子系统,流程解析

简单分层 应用层 内核层 --------------------------- input handler 数据处理层 driver/input/evdev.c1.和用户空间交互,实现fops2.不知道数据怎么得到的,但是可以把数据上传给用户--------------------------- input core层1.维护上面和下面的两个链表2.为上下两层提供接口--…

深度学习:欠拟合与过拟合

1 定义 1.1 模型欠拟合 AI模型的欠拟合&#xff08;Underfitting&#xff09;发生在模型未能充分学习训练数据中的模式和结构时&#xff0c;导致它在训练集和验证集上都表现不佳。欠拟合通常是由于模型太过简单&#xff0c;没有足够的能力捕捉到数据的复杂性和细节。 1.2 模型…

Python 自动化(十七)ORM操作

ORM-查询操作 查询简介 数据库的查询需要使用管理器对象 objects 进行 通过 自定义模型类.objects 管理器调用查询方法 查询方法 all()方法 概念与理解 用法&#xff1a;自定义模型类.objects.all()作用&#xff1a;查询自定义模型实体中所有的数据等同于 select * fr…

第八部分:JSP

目录 JSP概述 8.1&#xff1a;什么是JSP&#xff0c;它有什么作用&#xff1f; 8.2&#xff1a;JSP的本质是什么&#xff1f; 8.3&#xff1a;JSP的三种语法 8.3.1&#xff1a;jsp头部的page指令 8.3.2&#xff1a;jsp中的常用脚本 ①声明脚本&#xff08;极少使用&#xf…

【Python仿真】基于EKF的传感器融合定位

基于EKF的传感器融合定位&#xff08;Python仿真&#xff09; 简述1. 背景介绍1.1. EKF扩展卡尔曼滤波1.1.1.概念1.1.2. 扩展卡尔曼滤波的主要步骤如下&#xff1a;1.1.3. 优、缺点 1.2. 航位推算1.3. 目前航位算法的使用通常与卡尔曼滤波相结合使用2. 分段代码 2.1. 导入需要的…