模板初识与STL简介

news2024/12/23 14:11:11

初识模板

  • 引言
  • 函数模板
    • 定义
    • 实例化
      • 隐式实例化
      • 显式实例化
  • 类模板
    • 定义
    • 实例化
  • STL简介
    • STL六大组件
  • 总结

引言

模板是泛型编程的基础

在之前我们介绍过函数重载,可以定义许多函数名相同参数列表不同的重载函数,来实现不同类型的相似操作。调用重载函数时会根据传参调用一个合适的重载函数,这方便了调用这类方法。

但是,函数重载还是有一些不足:
重载的函数还是需要自己定义的,代码复用率不高。当需要增加一种类型的实现时,就需要我们再定义一个重载函数;重载函数的可维护性不高,如果出错了可能需要逐个修改每个重载函数。

泛型编程就可以解决这个问题,可以只写一份对所有类型通用的代码,在需要使用的时候由编译器生成相应的代码,是代码复用的一种手段。模板是泛型编程的基础

C++模板分为函数模板与类模板:
在这里插入图片描述

函数模板

函数模板代表了一类作用相同的函数,与类型无关。函数模板在使用时会由编译器自动实例化,生成一个特定类型的函数

定义

使用
template<typename T1, typename T2, ...typename Tn>
返回值 函数名(参数列表) {}
可以定义一个函数模板,其中typename也可以用class代替。

例如一个交换函数模板:


template<typename T>
void Swap(T& a, T& b)
{
	T temp = a;
	a = b;
	b = temp;
}

然后就可以像使用函数一样使用函数模板:

int main()
{
	int a = 10;
	int b = 20;
	Swap(a, b);
	cout << a << " " << b << endl;
	return 0;
}

在这里插入图片描述
需要注意的是,template声明的typename只在其接下来的函数内有效

实例化

在使用函数模板时,编译器会生成一个指定类型的函数,即函数模板的实例化。

在指定生成函数的类型时,就有两种方式,即隐式与显式:

隐式实例化

隐式实例化即编译器根据调用时的实参自动指定模板参数的类型:
例如这段代码:

template<typename T>
T Add(const T& a, const T& b)
{
	return a + b;
}
int main()
{
	int a = 10;
	int b = 20;
	cout << Add(a, b) << endl;
	return 0;
}

在这里插入图片描述
此时变量ab均为int,编译器自然可以通过两个均为int的实参推演出T的类型为int,这并不难理解。
但是当实参的类型不相同时,就无法确定T究竟是两个参数类型中的哪一个了:

	int a = 10;
	double b = 20;
	//cout << Add(a, b) << endl;  //错误代码,调用Add时模板参数不明确

在这里插入图片描述
在模板中,不会擅自进行类型转换。 比如这种情况,在类型T不明确时,并不确定要将int转化为double还是将double转换为int。

解决的方法当然也很简单:

  1. 可以在传参时将实参的类型显式的转换为一致:
template<typename T>
T Add(const T& a, const T& b)
{
	return a + b;
}
int main()
{
	int a = 10;
	double b = 20;
	cout << Add(a, (int)b) << endl;
	return 0;
}

在这里插入图片描述
需要注意的是,类型转换会生成一个临时变量,临时变量具有常性。所以如果模板的形参类型不是const修饰的话,就会发生权限放大,这种方法就是不可取的。

  1. 当然也可以显式的指定类型T,这样编译器就会尝试进行隐式类型转换,即显式实例化

显式实例化

显式实例化即在调用时函数名后的<>中显式的指定模板参数的类型: 函数名<模板参数列表>(实参列表);
例如上面的Add模板生成函数的调用:

int main()
{
	int a = 10;
	double b = 20;
	cout << Add<int>(a, b) << endl; // Add<int>(a, b)
	return 0;
}

在这里插入图片描述
当指定了模板参数的类型后,编译器当然就能在传参时进行隐式类型转换了,转换失败时就会报错。

需要注意的是:

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

例如:

int Add(const int& a, const int& b)
{
	return a + b;
}

template<typename T1, typename T2>
T1 Add(const T1& a, const T2& b)
{
	return a + b;
}
int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(1, 2.0) << endl;
	return 0;
}

在第一次调用Add函数时,实参类型均为int,所以优先调用非模板函数:
在这里插入图片描述
第二次调用Add函数时,第一个参数类型为int,第二个参数为double,模板生成的Add函数能更好的匹配,所以调用模板:
在这里插入图片描述
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换:

类模板

类似与函数,我们也可以定义一种与类型无关的类,即类模板。在使用时,再由编译器实例化为对于指定模板参数类型的类类型。

定义

使用
template<typename T1, typename T2, ...typename Tn>
class 类模板名 {};
可以定义一个函数模板,其中typename也可以用class代替。

例如我们可以写一个简陋的栈:

template<typename T>
class Stack
{
public:
	Stack(size_t size = 0, size_t capacity = 0)  //构造函数
		: _size(size)
		, _capacity(capacity)
		, _date(nullptr)
	{
		_date = new T[_capacity + 1]{ 0 };
	}
	void push(T n)    //压栈
	{
		if (_size == _capacity)
		{
			if (_capacity == 0)
			{
				reserve(6);
			}
			else
			{
				reserve(_capacity * 2);
			}
		}
		_date[_size] = n;
		++_size;
	}
	void reserve(size_t capacity)    
	{
		if (capacity > _capacity)
		{
			T* newdate = new T[capacity + 1]{ 0 };
			_capacity = capacity;
			for (int i = 0; i < _size; ++i)
			{
				newdate[i] = _date[i];
			}
			delete[] _date;
			_date = newdate;
		}
	}
	T top()
	{
		return _date[_size - 1];
	}
	size_t size()   
	{
		return _size;
	}
	~Stack()   //析构函数
	{
		delete[] _date;
		_size = 0;
		_capacity = 0;
	}
private:
	size_t _size;
	size_t _capacity;
	T* _date;
};

对于int型数据:

int main()
{
	Stack<int> nums;
	nums.push(1);
	nums.push(2);
	nums.push(3);
	nums.push(4);
	nums.push(5);
	cout << nums.top() << endl;
	cout << nums.size() << endl;
	return 0;
}

在这里插入图片描述
对于char型数据:

int main()
{
	Stack<char> str;
	str.push('a');
	str.push('b');
	str.push('c');
	str.push('d');
	str.push('e');
	cout << str.top() << endl;
	cout << str.size() << endl;
	return 0;
}

在这里插入图片描述
不难发现,对于不同的模板参数类型,这个简陋的栈可以实现其效果。

实例化

不同于函数模板,类模板不能通过参数来推断模板参数的类型,所以类模板的实例化必须在调用时的类模板名后的<>中显式指出模板参数。

例如对上面的栈模板的使用:

int main()
{
	//实例化类模板并实例化类对象
	Stack<char> str;
	Stack<int> nums;
	Stack<double> dnums;

	//对不同类型的栈堆栈
	str.push('a');
	str.push('b');
	nums.push(3);
	nums.push(4);
	dnums.push(20.0);
	dnums.push(30.0);

	//打印不同类型栈的栈顶元素及元素个数
	cout << str.top() << endl;
	cout << str.size() << endl;
	cout << nums.top() << endl;
	cout << nums.size() << endl;
	cout << dnums.top() << endl;
	cout << dnums.size() << endl;
	return 0;
}

在这里插入图片描述

需要注意的是:类模板名字不是真正的类,而实例化的结果才是真正的类

STL简介

STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架

STL六大组件

在这里插入图片描述
容器:string、vector、list、deque、map、set等
算法:find、swap、reverse、sort等

(这里只做了解,接下来将会逐渐详细介绍)

总结

到此,关于模板初阶的内容就介绍完了
包括函数模板与类模板

如果大家认为我对某一部分没有介绍清楚或者某一部分出了问题,欢迎大家在评论区提出

如果本文对你有帮助,希望一键三连哦

希望与大家共同进步哦

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

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

相关文章

chatgpt赋能python:归一化在PyTorch中的运用

归一化在PyTorch中的运用 PyTorch是一种广泛使用的深度学习框架&#xff0c;它可以用于训练和预测各种类型的神经网络。在深度学习中&#xff0c;归一化是提高模型性能的一种常用技术。归一化是指将输入数据进行标准化或规范化处理&#xff0c;以确保数据的统一性和一致性。在…

golang硬核技术(二)go程序从启动到运行到底经历了啥

前言 go相对其他语言&#xff0c;对并发的支持更友好。这使得他的设计和其他程序迥然不同。让我们来看看它都是如何初始化程序的&#xff0c;从程序加载到运行到底经历的什么。 我们继续之前的版本1.18.4 汇编入口 首先我们编译一个hello world 程序。 package main impor…

python--连接oracle数据库

python--连接oracle数据库 前言一、安装cx_Oracle二、导入库三、数据库操作实例3.1 连接3.2数据库查询3.3数据库插入3.4 实例从某网站上面爬取彩票号码 四、异常4.1、运行时&#xff0c;出现连接数据库失败:DatabaseError:DPI-1047解决连接失败问题1、查看Oracle的版本号2、进入…

辅助驾驶功能开发-功能规范篇(21)-1-XP行泊一体方案功能规范

XPilot Safety 主动安全系统 一、前向碰撞预防(Forward Collision Prevention) - 产品定义 基于车辆前向视觉模块和前毫米波雷达的感知能力,对车辆前方扇形区域内的车辆和VRU(弱势道路使用者) 有可能与本车的运行路线发生碰撞,进行预警、碰撞伤害降低或碰撞避免的一系列…

QT 简易视频播放器版本1.1

设计Qt界面实现播放、暂停、停止、下一集、上一集、快进、后退、倍速播放、进度调节&#xff0c;音量调节、视频播放列表等功能 先上演示效果&#xff1a; ui界面设计 videoplayer.h #ifndef VIDEOPLAYER_H #define VIDEOPLAYER_H#pragma execution_character_set("utf-…

深入了解Promise机制并使用JS实现一个Promise(一)

前言 关于为什么会有Promise以及Promise的一些用法和基本机制可以参考之前的文章JS中的异步与Promise使用整体来说&#xff0c;Promise可以帮助我们很好的解决异步的问题&#xff0c;号称是异步的终极解决方案。在浏览器中Promise是使用C实现的&#xff0c;今天就使用js来实现…

JSP原理以及基本语法

1、JSP原理 什么是JSP&#xff1f; Java Server Pages&#xff1a;Java服务器页面&#xff0c;和Servlet一样是动态Web技术&#xff01; 和HTML的区别&#xff1f; HTML是静态页面。在JSP页面中可以嵌入Java代码&#xff0c;为用户提供动态的数据。 JSP 和 Servlet 的关系…

枚举一个进程中的所有线程

在 Win32 开发中&#xff0c;如果需要获取程序运行过程中的一些较为底层的信息&#xff0c;你可能需要使用到 Tool Helper 库。但我愿意称之它为 Win32 中的 “害群之马”。何解&#xff1f; Tool Helper 库在 16 位 Windows 时代就已经存在了&#xff0c;这个库主要用来提供一…

今天给我的Ubuntu服务器挂在了一个4T的硬盘却只能识别到2T,原来是因为这!涨知识了

前言 今天买的4T机械硬盘到了&#xff0c;准备给我的服务器加装上&#xff0c;用来作为Nextcloud的存储硬盘。把硬盘安装好后就迫不及待的进行挂载&#xff0c;挂载的操作倒是挺顺利的&#xff0c;但是无论怎么操作Ubuntu系统识别到的大小居然都是2T&#xff0c;最后没办法&am…

chatgpt赋能python:开方在Python中的用法

开方在Python中的用法 开方是数学中常见的一种运算&#xff0c;用于求一个数的平方根。在Python中&#xff0c;开方运算可以通过使用math模块中的sqrt函数来实现。本文将介绍开方运算的概念、Python中的应用以及一些常见问题的解决方法。 开方的概念 开方是指&#xff0c;对…

chatgpt赋能python:在Python中运行程序的方法介绍

在Python中运行程序的方法介绍 Python是一种广泛使用的编程语言&#xff0c;也是人工智能和数据科学领域的首选。在这篇SEO文章中&#xff0c;我们将介绍Python中运行程序的几种方法。 1. 在Python环境中运行程序 Python环境是一个Python解释器及其标准库的集合。为了在Pyth…

Redis7【⑥ Redis复制(replica)】

Redis复制 Redis 复制&#xff08;Replication&#xff09;是 Redis 的一项核心功能&#xff0c;用于将一个 Redis 数据库的所有数据复制到另一个 Redis 实例上。Redis 复制可以提高系统的可用性、可靠性和扩展性&#xff0c;使得在发生故障时可以快速地恢复数据。 Redis 复制…

【TiDB v7.1.0】资源管控调研及评测

作者&#xff1a; angryart 原文来源&#xff1a; https://tidb.net/blog/ad24240a 多租户是什么 有语云&#xff0c;食在广州&#xff0c;玩在杭州&#xff0c;死在柳州&#xff0c;广东人除了天上飞的飞机不吃&#xff0c;地上走的坦克不吃&#xff0c;其它的什么都吃&am…

Mybatis面试题--MyBatis一级缓存,二级缓存

Mybatis的一级、二级缓存用过吗&#xff1f; 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存&#xff0c;其存储作用域为 Session&#xff0c;当Session进行flush或close之后&#xff0c;该Session中的所有Cache就将清空&#xff0c;默认打开一级缓存 二级缓存 是基于n…

Python将多维列表「拉伸」为一维列表的10种方式

来源&#xff1a;投稿 作者&#xff1a;Fairy 编辑&#xff1a;学姐 在Python编程中&#xff0c;列表是一种常用的数据类型。当我们遇到了一个嵌套列表&#xff0c;如果想将它扁平化为一维列表&#xff0c;就可以使用下面10种方法之一来实现这个需求。 1. 使用两层循环遍历 l…

【记录】实践场景

Apache Doris 在京东搜索实时 OLAP 探索与实践 https://doris.apache.org/zh-CN/blog/JD_OLAP/ 通过对比开源的几款实时OLAP引擎&#xff0c;我们发现doris和clickhouse能够满足我们的需求&#xff0c;但是clickhouse的并发度太低是个潜在的风险&#xff0c;而且clickhouse的数…

已将该虚拟机配置为使用 64 位客户机操作系统。但是,无法执行 64 位操作。

错误提示&#xff1a; 一般只有下面几种方法 百度经验解决方法 http://jingyan.baidu.com/article/90bc8fc859b481f653640cac.html http://jingyan.baidu.com/article/25648fc1bfd4a29190fd0067.html 2.第二种方法 检测问题所在&#xff1a; 下载LeoMoon CPU-V 检查一下CP…

小程序本地生活

2023年7月1号 感觉就是视频要快点看不完 不然哪天接口又失效了 Page({/*** 页面的初始数据*/data: {// 存放轮播图的数据swiperList:[],// 存放九宫格的数据gridList:[]},/*** 生命周期函数--监听页面加载*/onLoad(options) {this.getSwiperList()this.getGridList()},// 获…

【GIS】阿里AI Earth选择内置地图

说明 aie.Map&#xff0c;构造一个地图组件Map对象&#xff0c;用于可视化渲染计算结果。坐标系固定为EPSG:4326。 阿里AI Earth中&#xff0c;坐标系默认为EPSG:4326 效果 import aie aie.Authenticate() aie.Initialize() my_province aie.FeatureCollection(China_Provin…

【Python】Python基础笔记

Python基础笔记 数据的输入和输出 print("数据") # 这是数据的输出 name input() # 这是数据的输入&#xff0c;并将输入的数据赋值给name。而且无论输入的何种类型的数据&#xff0c;最终的结果都是 字符串 类型的数据pint 输出不换行&#xff1a; # print 输出…