模板和STL简介

news2024/11/20 8:31:30

模板和STL简介

  • 一、泛型编程
    • 1、通用交换函数的实现
      • (1)代码
      • (2)总结
    • 2、泛型编程的概念
    • 3、模板的概念
  • 二、函数模板
    • 1、概念
    • 2、格式
    • 3、代码
    • 4、原理
  • 三、函数模板实例化
    • 1、概念
    • 2、隐式实例化
      • (1)概念
      • (2)代码
      • (3)运行结果
      • (4)错误代码与编译器报错
      • (5)错误代码解释
    • 3、显式实例化
      • (1)概念
      • (2)代码
      • (3)运行结果
    • 4、模板参数的匹配原则
      • (1)原则
      • (2)示例代码1
      • (3)示例代码2
  • 四、类模板
    • 1、格式
    • 2、代码
    • 3、讲解
    • 4、运行结果
    • 5、错误代码与编译器报错
  • 五、STL
    • 1、概念
    • 2、六大组件
    • 3、缺陷

一、泛型编程

1、通用交换函数的实现

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

//…………

(2)总结

  • 使用函数重载虽然可以实现一个通用的交换函数,但是使用这种方法有几个不好的地方。
  • 重载的函数只有形参的类型不同,其他的都一样,这样的代码复用率比较低,当要进行操作的对象的类型不同时,就需要用户自己添加对应类型的函数。
  • 代码的可维护性比较低,一个函数出错可能所有的重载函数均会出错。

2、泛型编程的概念

  • 泛型:不使用具体的数据类型,而是使用一种通用类型 T 来进行程序设计;这里的T 只是一个占位符,实际在 T 的位置,它的真实数据类型取决于用户的需求;占位符的替换由编译器在编译阶段完成。
  • 泛型编程:为了避免因数据类型的不同,而被迫重复编写大量相同业务逻辑的代码,因此发展了泛型及泛型编程技术;即泛型编程就是独立于任何特定类型的方式去编写代码。
  • 编写与类型无关的通用代码,是代码复用的一种手段。

3、模板的概念

建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。这种通用的方式称为模板。而模板是泛型编程的基础。
在这里插入图片描述

二、函数模板

1、概念

函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,即编译器自动依据实参的类型推演函数形参的类型,再根据推演出来的类型生成具有特定类型的函数版本。

2、格式

  • template<typename T1, typename T2,…,typename Tn>
  • 返回值类型 函数名(参数列表){}
  • typename是用来定义模板参数的关键字,它可以使用class替换,但不能使用struct代替class。虽然class和struct都有类的定义,但在此处它们的作用是不相同的。
  • typename后面的类型名字T是随便取的,取T是因为采用type的缩写,还可以写为Ty、K、V等等,但一般都是大写字母或者单词首字母大写。
  • T 代表的是一个模板类型(虚拟类型)。

3、代码

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

4、原理

函数模板就像一个蓝图,它本身并不是一个函数,而是编译器用使用方式产生特定具体类型函数的模具。所以模板就是将本来应该我们做的重复事情交给编译器去做,即还是会生成特定的函数,而不是说调用函数时直接使用模板进行操作。
在这里插入图片描述

  • 例如,当用double类型的参数使用函数模板时,编译器通过对实参类型进行推演,将T确定为double类型,然后产生一个专门处理double类型的函数,对于其他类型的参数也是如此。

三、函数模板实例化

1、概念

用不同类型的参数使用函数模板时,称为函数模板的实例化。而实例化有两种,即隐式实例化和显式实例化。

2、隐式实例化

(1)概念

在发生函数调用的时候,如果没有找到相匹配的函数存在,编译器就会寻找同名函数模板,如果进行参数类型推演可以成功,就对函数模板进行实例化。

(2)代码

template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}

void Test1()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.5, d2 = 20.5;
	cout << Add(a1, a2) << endl;
	cout << Add(d1, d2) << endl;
	//cout << Add(a1, d2) << endl;

	cout << Add((double)a1, d2) << endl;

	return 0;
}

(3)运行结果

在这里插入图片描述

(4)错误代码与编译器报错

在这里插入图片描述
在这里插入图片描述

(5)错误代码解释

  • 该语句之所以不能通过编译,是因为在编译期间,当编译器执行到该实例化语句时,需要推演其形参类型,而通过实参a1将T推演为int类型,通过实参d1将T推演为double类型,但模板参数列表中只有一个T。
  • 因此,编译器无法确定此处到底该将T确定为int类型还是double类型而报错。
  • 在模板中,编译器一般不会进行类型转换的操作,因为一旦转化出问题,编译器就需要背黑锅。
  • 此时有两种处理方式,第一种为用户自己将实参进行强制类型转化,使传递的实参只有一个类型。如代码中的最后一条语句;第二种为使用显式实例化。

3、显式实例化

(1)概念

在函数名后的<>中指定模板参数的实际类型,使函数模板生成特定类型的函数,从而避免在使用模板时重复编译相同的模板代码,或者模板T只有一个类型,而传递的实参的类型却不止有一个时,即编译器推演的形参类型与模板的参数类型不匹配时,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

(2)代码

int main()
{
	int a = 10;
	double d = 10.5;
	cout << Add<int>(a, d) << endl;
	cout << Add<double>(a, d) << endl;
	
	return 0;
}

(3)运行结果

在这里插入图片描述

4、模板参数的匹配原则

(1)原则

  • 一个非模板函数和一个同名的函数模板可以同时存在,而且该函数模板还可以被实例化为这个非模板函数。
  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调用时会优先调用非模板函数而不会从函数模板中实例化一个函数。如果模板函数可以产生一个参数匹配更好的函数,那么将选择函数模板去实例化一个函数。
  • 模板函数不允许自动类型转换,但普通函数却可以进行自动类型转换。

(2)示例代码1

int Add(int x, int y)
{
	return x + y;
}

template<typename T>
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a1 = 10, a2 = 20;
	cout << Add(a1, a2) << endl;
	cout << Add<int>(a1, a2) << endl;

	return 0;
}
  • 第一个Add函数调用时,将调用非模板函数,第二个因为使用显式实例化,所以它将用函数模板实例化出一个非模板函数,而这个实例化出来的函数和已存在的非模板函数一样。

(3)示例代码2

int Add(int x, int y)
{
	return x + y;
}

template<class T1,class T2>
T1 Add(const T1& x, const T2& y)
{
	return x + y;
}

int main()
{
	cout << Add(10, 20) << endl;
	cout << Add(10, 20.5) << endl;

	return 0;
}
  • 第一个Add函数调用时,它的实参与非模板函数的形参类型完全匹配,所以不需要使用函数模板去实例化一个函数。
  • 第二个Add函数调用时,模板函数可以生成更加匹配的函数,则编译器会根据实参使用模板函数去生成一个更加匹配的Add函数。

四、类模板

1、格式

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

2、代码

template<typename T>
class Stack
{
public:
	Stack(size_t capacity = 0)
	{
		if (capacity > 0)
		{
			_a = new T[capacity];
			_capacity = capacity;
			_top = 0;
		}
	}

	~Stack()
	{
		delete[] _a;
		_a = nullptr;
		_capacity = _top = 0;
	}

	void Push(const T& x);

	void Pop()
	{
		assert(_top > 0);
		--_top;
	}

	bool Empty()
	{
		return _top == 0;
	}

	const T& Top()
	{
		assert(_top > 0);
		return _a[_top - 1];
	}
private:
	T* _a = nullptr;
	size_t _top = 0;
	size_t _capacity = 0;
};

template<class T>
void Stack<T>::Push(const T& x)
{
	if (_top == _capacity)
	{
		size_t newCapacity = _capacity == 0 ? 4 : _capacity * 2;
		// 1、开辟新空间 2、拷贝数据 3、释放旧空间
		T* tmp = new T[newCapacity];
		if (_a)
		{
			memcpy(tmp, _a, sizeof(T)*_top);
			delete[] _a;
		}

		_a = tmp;
		_capacity = newCapacity;
	}

	_a[_top] = x;
	++_top;
}


int main()
{
	try
	{
		/*Stack<> st1;
		Stack st2;*/

		Stack<int> st3;
		Stack<char> st4;

		Stack<int> st5(10);

		st3.Push(1);
		st3.Push(2);
		st3.Push(3);
		st3.Push(4);
		st3.Push(5);

		/*st3.Top()++;
		st3.Top() *= 2;*/

		while (!st3.Empty())
		{
			cout << st3.Top() << " ";
			st3.Pop();
		}
		cout << endl;

	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	
	return 0;
}

3、讲解

  • 上方代码是一个Stack的类模板,但它不是具体的类,而是编译器根据被实例化的类型而生成具体类的模板。
  • 虽然模板不支持分离编译,即不支持声明放在.h头文件,定义放在.cpp源文件中。但当模板在同一个文件中时,是可以声明和定义分离的。即如上方代码中的Push成员函数。而当类模板中的成员函数放在类外进行定义时,需要加模板参数列表(template< class T>)。
  • 类模板都需要显示实例化,虽然实例化出来的类都用了同一个类模板,但它们并不是同一个类型。
  • 类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将欲实例化的类型放在<>中,如上方代码中的st3和st4。但需要注意的是类模板名字不是真正的类,而实例化后的结果才是真正的类,即Stack是类名,而Stack< int >才是类型。
  • 当知道对象需要存储数据的数量时,可以如上方代码中的st5一样,在()中输入欲存储数据的数量,这样的操作能避免在插入数据时进行扩容的消耗。
  • try和catch的作用是捕获异常,即当new开辟空间失败抛出异常时,会对被抛出的异常进行捕获。
  • 类模板中的Top成员函数是用const修饰的,当调用Top函数时,不能对其进行修改,如要对其进行修改则需要去掉const。

4、运行结果

在这里插入图片描述

5、错误代码与编译器报错

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

五、STL

1、概念

  • STL(Standard Template Library),即标准模板库,它是一个高效的C++程序库,包含了诸多常用的基本数据结构和基本算法。为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
  • 从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming)。在这种思想里,大部分基本算法被抽象,被泛化,独立于与之对应的数据结构,用于以相同或相近的方式处理各种不同的情形。
  • 从实现层次来看,整个STL是以一种类型参数化(type parameterized)的方式实现的,即是基于模板(template)的。

2、六大组件

在这里插入图片描述

3、缺陷

  • STL库的更新太慢了。它的上一个靠谱的版本是C++98,中间的C++03添加了一些修订。到C++11出来时已经过了13年,STL才得到了进一步的更新。
  • STL现在都没有支持线程安全。并发环境下需要我们自己加锁,且锁的粒度比较大。
  • STL极度地追求效率,导致内部比较复杂。比如,类型萃取,迭代器萃取。
  • STL的使用会有代码膨胀的问题,比如使用vector/vector/vector这样会生成多份代码。当然,这是模板语法本身导致的。

本文到这里就结束了,如有错误或者不清楚的地方欢迎评论或者私信
创作不易,如果觉得博主写得不错,请务必点赞、收藏加关注💕💕💕

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

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

相关文章

传输层—TCP原理详解

目录 前言 1.TCP协议 2.TCP协议段格式 3.如何解包如何分用 4.网络协议栈和文件的关系 5.如何理解TCP报头 6.TCP的特点 7.TCP字段 7.1 16位窗口大小 7.2标志位 8.超时重传 9.连接管理机制 10.滑动窗口 11.拥塞控制 12.延迟应答 13.捎带应答 14.理解TCP的面向字…

【算法系列篇】分冶-快排

文章目录 前言什么是分冶1.颜色分类1.1 题目要求1.2 做题思路1.3 Java代码实现 2. 排序数组2.1 题目要求2.2 做题思路2.3 Java代码实现 3.数组中的第k个最大元素3.1 题目要求3.2 做题思路3.3 Java代码实现 4. 最小的k个数4.1 题目要求4.2 做题思路4.3 Java代码实现 总结 前言 …

MYSQL调优之思路----sql语句和索引调优

MySQL数据库性能优化包括综合多方面因素&#xff0c;应根据实际的业务情况制定科学、合理的调优方案进行测试调优 文章目录 MySQL性能优化1 优化介绍1.2 优化要考虑的问题2.1 优化可能带来的问题2.2 优化的需求2.3 优化由谁参与2.4 优化的方向2.5 优化的维度 1.2数据库使用优化…

【SpringMVC】工作流程及入门案例

目录 前言 回顾MVC三层架构 1. SpringMVC简介 …

虹科资讯 | LyoPro 作为领先的冻干验证解决方案获得美国和欧洲两项官方专利!

获得美国和欧洲两项官方专利 我们非常高兴地宣布&#xff0c;虹科LyoPro冻干专用温度验证仪已在美国和欧洲获得两项官方专利&#xff0c;巩固了其作为市场上同类解决方案的唯一地位。有关LyoPro温度记录仪的专利分别是 US11340015B2 和 EP3742095B1&#xff0c;前者于2022年5月…

如何实现MongoDB数据的快速迁移?

作为一种Schema Free文档数据库&#xff0c;MongoDB因其灵活的数据模型&#xff0c;支撑业务快速迭代研发&#xff0c;广受开发者欢迎并被广泛使用。在企业使用MongoDB承载应用的过程中&#xff0c;会因为业务上云/跨云/下云/跨机房迁移/跨地域迁移、或数据库版本升级、数据库整…

【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_SPEED_OPTIMIZER

文章目录 前言PIECEWISE_JERK_SPEED_OPTIMIZER功能简介PIECEWISE_JERK_SPEED_OPTIMIZER相关配置PIECEWISE_JERK_SPEED_OPTIMIZER流程QP问题的标准类型定义&#xff1a;优化变量设计目标函数约束条件相关矩阵二次项系数矩阵 H H H一次项系数向量 q q q设定OSQP求解参数 Process设…

第二张微服务的调用与注册

文章目录 工程导入利用RestTemplate调用服务需求创建RestTemplate的实例到Spring容器使用RestTemplate发送请求消费者和提供者 Eureka注册中心服务远程调用会出现的问题Eureka的结构和作用Eureka的配置过程搭建注册中心服务注册服务发现 Ribbon负载均衡负载均衡原理源码跟踪总结…

windows server 2019 一键安装sqlserver2012

准备安装包和脚本 脚本代码 install.bat REM 自动判断权限问题&#xff0c;主动获取管理员权限 >nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system" if %errorlevel% NEQ 0 ( goto UACPrompt ) else ( go…

PPT 架构师三板斧

PPT 架构师三板斧 目录概述需求&#xff1a; 设计思路实现思路分析1.多节点上PPT 架构师三板斧2.几张框框组合有组织3.专业词汇4.切记点要点 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;ski…

使用Jekyll + GitHub Pages搭建个人博客

本文将介绍如何使用Jekyll搭建个人博客&#xff0c;并部署在GitHub Pages上。 1.简介 Jekyll是一个强大的静态网站生成器&#xff0c;可以将Markdown、HTML、Liquid模板等文件转换为静态网站。Jekyll支持模板引擎、主题、插件、集成GitHub Pages等特性&#xff0c;可以帮助用…

GeoServe Web管理界面远程访问GeoServe Web管理界面的最佳工具

文章目录 前言1.安装GeoServer2. windows 安装 cpolar3. 创建公网访问地址4. 公网访问Geo Servcer服务5. 固定公网HTTP地址 前言 GeoServer是OGC Web服务器规范的J2EE实现&#xff0c;利用GeoServer可以方便地发布地图数据&#xff0c;允许用户对要素数据进行更新、删除、插入…

网络编程 day 7

1、将.txt表数据导入数据库中 #include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr,"__%d__:",__LINE__);\perror(msg);\ }while(0)int main(int argc, const char *argv[]) {//以只读的方式打开dict.txt文件FILE* fd;if((fdfopen("./dict.txt&q…

C++多态案例2----制作饮品

#include<iostream> using namespace std;//制作饮品的大致流程都为&#xff1a; //煮水-----冲泡-----倒入杯中----加入辅料//本案例利用多态技术&#xff0c;提供抽象类制作饮品基类&#xff0c;提供子类制作茶叶和咖啡class AbstractDrinking {public://煮水//冲水//倒…

springboot整合elasticsearch使用案例

引入依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency> 添加注入 import org.apache.http.HttpHost; import org.elasticsearch.client.Res…

关于右值引用与完美转发

关于右值引用与完美转发 今日的疑问: 在下面的代码中,forwardFunction(n); // 为什么这里调用的是process(int&),而不是process(int&&)?解答:想要使用右值的方法有很多,如下: 今日的疑问: 在下面的代码中,forwardFunction(n); // 为什么这里调用的是process(int&a…

sql:SQL优化知识点记录(十)

&#xff08;1&#xff09;慢查询日志 Group by的优化跟Order by趋同&#xff0c;只是多了一个having 开启慢查询日志&#xff1a; 演示一下慢sql&#xff1a;4秒之后才会出结果 查看一下&#xff1a;下方显示慢查询的sql &#xff08;2&#xff09;批量插入数据脚本 函数和存…

大模型 Dalle2 学习三部曲(一)Latent Diffusion Models学习

引言 Diffusion model大获成功&#xff0c;但是它的短板也很明显&#xff0c;需要大量的计算资源&#xff0c;并且推理速度比较慢。如何才能提升Diffusion model的计算效率。业界有各种各样的改进&#xff0c;无疑Latent Diffusion Models&#xff08;潜在扩散模型&#xff0c;…

SpringMVC入门详细介绍

一. SpringMVC简介 Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架&#xff0c;通过把Model&#xff0c;View&#xff0c;Controller分离&#xff0c;将web层进行职责解耦&#xff0c;把复杂的web应用分成逻辑清晰的几部分&#xff0c;简化开发&a…

Redis面试题(笔记)

目录 1.缓存穿透 2.缓存击穿 3.缓存雪崩 小结 4.缓存-双写一致性 5.缓存-持久性 6.缓存-数据过期策略 7.缓存-数据淘汰策略 数据淘汰策略-使用建议 数据淘汰策略总结 8.redis分布式锁 setnx redission 主从一致性 9.主从复制、主从同步 10.哨兵模式 服务状态监…