02c++模板部分讲解

1理解函数模板

#include<iostream>
using namespace std;

//函数模板
template<typename T> //定义一个模板参数列表
//模板类型参数 typename/class
bool compare(T a, T b)
{
	cout << "template compare: " << endl;
	return a > b;
}

template<>
bool compare(const char* a, const char* b)
{
	cout << "compare(char*)";
	return strcmp(a, b) > 0;
}

//非模板函数
bool compare(const char* a, const char* b)
{
	cout << "normal compare: " << endl;
	return strcmp(a, b) > 0;
}
/*函数调用点,编译器用用户指定的类型,从原来的模板实例化一份函数代码出来*/
int main()
{
	compare<int>(10, 20);
	compare(20, 30); //推导出来是整形 模板实参法推演

	//compare(30, 4.5);b报错,找不到
	compare<int>(30, 3.4); //这样子可以但是被会警告
	//对于某些类型来说,依赖编译器默认实例化的模板代码,代码处理逻辑是有错误的
	compare("aaa", "bbb"); //不能a>b来处理
	//模板的特例化,不是编译器提供的,而是用户提供的实例化
	return 0;
}
//份文件的时候 直接告诉编译器模板指定类型的模板实例化
template bool compare<int>(int, int);
template bool compare<double>(double, double);

2、理解类模板

#include<iostream>
using namespace std;


template<typename T, const int SIZE>
void sort(T* arr)
{
	for (int i = 0; i < SIZE - 1; i++)
	{
		for (int j = 0; j < SIZE - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}
//类模板
int main()
{
	int arr[] = { 12,2,2,2,2,2 };
	const int size = sizeof(arr) / sizeof(arr[0]);
	sort<int, size>(arr);
	for (int val : arr)
	{
		cout << val << " ";
	}
	cout << endl;
}

#include<iostream>
using namespace std;
#include<time.h>
template<typename T> //模板+参数列表 = 类名称
class SeqStack
{
public:
	//构造函数和析构函数不要加模板类型参数列表
	SeqStack(int size = 10)
		:_stack(new T[size]),
		_top(0),
		_size(size)
	{}
	~SeqStack()
	{
		delete[]_stack;
		_stack = nullptr;
	}
	SeqStack<T>(const SeqStack<T>& stack)
		:_top(stack._top),
		_size(stack._size)
	{
		_stack = new T[_size];
		//不要用memcopy进行拷贝
		for (int i = 0; i < _top; i++)
		{
			_stack[i] = stack._stack[i];
		}
	}
	SeqStack<T>& operator = (const SeqStack<T>& stack)
	{

		if (this == &stack)return *this;
		delete[] _stack;
		_top = stack._top;
		_size = stack._size;
		_stack = new T[_size];
		//不要用memcopy进行拷贝
		for (int i = 0; i < _top; i++)
		{
			_stack[i] = stack._stack[i];
		}
		return *this;
	}

	void push(const T& val)
	{
		if (full())expand();
		_stack[_top++] = val;
	}
	void pop()
	{
		if (empty())
		{
			return;
		}
		--_top;
	}
	T top() const
	{
		if ((empty()))throw "stack is empty()"; //抛出异常结束
		return _stack[_top - 1];
	}
	bool full()const
	{
		return _top == _size;
	}
	bool empty()const
	{
		return _top == 0;
	}
private:
	T* _stack;
	int _top;
	int _size;
	//顺序栈底层数
	void expand()
	{
		T* ptmp = new T[_size * 2];
		for (int i = 0; i < _top; i++)
		{
			ptmp[i] = _stack[i];
		}
		delete[]_stack;
		_stack = ptmp;
		ptmp = nullptr;
		_size *= 2;
	}
};
int main()
{
	SeqStack<int>stack(4);
	for (int i = 0; i < 20; i++)
	{
		stack.push(rand() % 100);
	}
	while (!stack.empty())
	{
		cout << stack.top() << " ";
		stack.pop();
	}

	cout << endl;
	SeqStack<int>stack1(2);
	stack1.push(1);
	stack1.push(2);
	stack1.push(3);
	stack1.push(4);
	stack1.pop();
	cout << stack1.top();

	return 0;
}

3、SLT实现Vector类

#include<iostream>
using namespace std;

template<class T>
class Vector
{
public:
	Vector(int size = 10)
	{
		_first = new T[size];
		_last = _first;
		_end = _first + size;
	}

	~Vector()
	{
		delete[]_first;
		_first = _last = _end = nullptr;
	}

	Vector(const Vector<T>& rhs)
	{
		int size = rhs._end - rhs._first;
		_first = new T[size]; //空间大小
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; i++)
		{
			_first[i] = rhs._first[i];
		}
		_last = _first + len;
		_end = _first + size;
	}
	Vector<T>& operator=(const Vector<T>& rhs) //拷贝构造
	{
		if (this == &rhs)return *this;
		delete[] _first;
		int size = rhs._end - rhs._first;
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; i++)
		{
			_first[i] = rhs._first[i];
		}
		_last = _first + len;
		_end = _first + size;
		return *this;
	}

	void push_back(const T& val)
	{
		if (full())
		{
			expand();
		}
		*_last = val;
		_last++;
	}

	void pop_back()
	{
		if (empty())
		{
			return;
		}
		--_last;
	}
	T back()const //返回容器末尾的元素值
	{
		return *(_last - 1);
	}

	bool full()const { return _last == _end; }
	bool empty()const { return _first == _last; }
	int size()const { return _last - _first; }

private:

	void expand()
	{
		int _size = _end - _first;
		T* tmp = new T[_size * 2];
		for (int i = 0; i < _size; i++)
		{
			tmp[i] = _first[i];
		}
		delete[]_first;
		_first = tmp;
		_last = _first + _size;
		_size *= 2;
		_end = _first + _size;
	}
	T* _first; //指向数组的起始的位置
	T* _last; //指向数组有效元素的后继位置
	T* _end; //指向数组空间的后继位置

};
//容器空间分配器
class Test
{
public:
	Test() { cout << "test()" << endl; }
	~Test() { cout << "~test()" << endl; }
};

int main()
{/*
	Vector<int>vec;
	for (int i = 0; i < 20; i++)
	{
		vec.push_back(rand() % 100);
	}
	while (!vec.empty())
	{
		cout << vec.back() << " ";
		vec.pop_back();
	}
	cout << endl;
	vec.push_back(10);
	cout << vec.back() << endl;
	cout << endl;*/
	Vector<Test>vec;
	return 0;
}

6、容器空间配置

#include<iostream>
using namespace std;



/*
template <class _Ty,
	class _Alloc = allocator<_Ty>>
	class Vector
	容器的空间配置器allocator做四件事情 内存开辟 内存释放 对象构造 对象析构
*/

//定义容器的空间配置器,和c++标准库的allocator实现一样
template<typename T>
class Allocator
{
public:
	T* allocate(size_t size) //负责内存开辟
	{
		return (T*)malloc(sizeof(T) * size);

	}

	void deallocate(void* p) //负责内存释放
	{
		free(p);
	}

	void construct(T* p, const T& val) //负责对象构造
	{
		new (p) T(val);//定位new
	}
	void destroy(T* p)//负责对象析构
	{
		p->~T();//代表了T类型的析构函数
	}
};
template<typename T, typename Alloc = Allocator<T>>
class Vector
{
public:
	Vector(int size = 10)
	{
		//需要把内存开辟和对象构造分开处理
		//_first = new T[size];
		_first = _allocator.allocate(size);

		_last = _first;
		_end = _first + size;
	}

	~Vector()
	{
		//delete[]_first;
		//析构有效的元素,然后释放_first指针指向的堆内存
		for (T* p = _first; p != _last; p++)
		{
			_allocator.destroy(p); //把first指针指向的数组的有效元素进行析构操作
		}
		_allocator.deallocate(_first);//释放堆上的数组内存
		_first = _last = _end = nullptr;
	}

	Vector(const Vector<T>& rhs)
	{
		int size = rhs._end - rhs._first;
		//_first = new T[size]; //空间大小
		_first = _allocator.allocate(size);
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; i++)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}

		_last = _first + len;
		_end = _first + size;
	}
	Vector<T>& operator=(const Vector<T>& rhs) //拷贝构造
	{
		if (this == &rhs)return *this;
		//delete[] _first;
		for (T* p = _first; p != _last; p++)
		{
			_allocator.destroy(p); //把first指针指向的数组的有效元素进行析构操作
		}
		_allocator.deallocate(_first);//释放堆上的数组内存

		int size = rhs._end - rhs._first;
		int len = rhs._last - rhs._first;
		for (int i = 0; i < len; i++)
		{
			//_first[i] = rhs._first[i];
			_allocator.construct(_first + i, rhs._first[i]);
		}
		_last = _first + len;
		_end = _first + size;
		return *this;
	}

	void push_back(const T& val)
	{
		if (full())
		{
			expand();
		}
		//*_last = val;
		_allocator.construct(_last, val);
		_last++;
	}

	void pop_back()
	{
		if (empty())
		{
			return;
		}
		//--_last;
		--_last;
		_allocator.destroy(_last);
	}
	T back()const //返回容器末尾的元素值
	{
		return *(_last - 1);
	}

	bool full()const { return _last == _end; }
	bool empty()const { return _first == _last; }
	int size()const { return _last - _first; }

private:

	void expand()
	{
		int _size = _end - _first;
		//T* tmp = new T[_size * 2];
		T* tmp = _allocator.allocate(2 * _size);
		for (int i = 0; i < _size; i++)
		{
			//tmp[i] = _first[i];
			_allocator.construct(tmp + i, _first[i]);
		}
		//delete[]_first;
		for (T* p = _first; p != _last; p++)
		{
			_allocator.destroy(p);
		}
		_allocator.deallocate(_first);
		_first = tmp;
		_last = _first + _size;
		_end = _first + 2 * _size;
	}
	T* _first; //指向数组的起始的位置
	T* _last; //指向数组有效元素的后继位置
	T* _end; //指向数组空间的后继位置

	Alloc _allocator;//定义i容器中的空间配置项

};
//容器空间分配器
class Test
{
public:
	Test() { cout << "test()" << endl; }
	~Test() { cout << "~test()" << endl; }
	Test(const Test&) { cout << "Test(const Test&)" << endl; }
};

int main()
{
	Test t1, t2, t3;
	cout << "----------" << endl;
	Vector<Test>vec;

	vec.push_back(t1);
	vec.push_back(t2);
	vec.push_back(t3);
	cout << "----------" << endl;
	vec.pop_back(); //只需要析构
	cout << "----------" << endl;


	return 0;
}

在这里插入图片描述

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

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

相关文章

centos7.9系统rabbitmq3.8.5升级为3.8.35版本

说明 本文仅适用rabbitmq为RPM安装方式。 升级准备 查看环境当前版本&#xff1a; # cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) # rabbitmqctl status Status of node rabbitmq01 ... RuntimeOS PID: 19333 OS: Linux Uptime (seconds): 58 Is under …

Blazor入门-基础知识+vs2022自带例程的理解

参考&#xff1a; Blazor 教程 - 生成首个应用 https://dotnet.microsoft.com/zh-cn/learn/aspnet/blazor-tutorial/intro Blazor基础知识&#xff1a;Visual Studio 2022 中的Blazor开发入门_vs2022 blazor webassembly-CSDN博客 https://blog.csdn.net/mzl87/article/detail…

【Unity自制手册】unity常用API大全——一篇文章足以(十万字详解)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 收录于专栏 unity 实战系列 ⭐相关文章⭐ ⭐【软件设计师高频考点暴击】 -本站最全-unity常用API大全&#xff08;万字…

性能测试 --概念

什么是性能测试 性能测试和功能测试都是在系统测试阶段运行, 两者有什么区别呢? 案例:豌豆射手和三线射手都是射手, 它们的功能都是向前发射豌豆进行攻击, 能够攻击到地面的僵尸. 但是从性能上来讲, 豌豆射手只能攻击到一路的僵尸, 而三线射手能同时攻击三路(注:放在边路实际…

如何统计区域内部公路总长度和绘制数据直方图

交通对区域经济发展具有重要的意义&#xff0c;诸多经济学文献均对此进行了深入探讨&#xff0c;那么如何在ArcGIS上统计区域内部交通路线的总长度呢&#xff1f;本文以全国各省份主要公路总长度为例详细介绍了相关ArcGIS以及统计直方图的操作。 工具&#xff1a; 使用ArcGIS中…

【JavaScript】内置对象 - 数组对象 ③ ( 数组反转 - reverse 方法 | 数组排序 - sort 方法 | 自定义数组排序规则 )

文章目录 一、数组排序1、翻转数组元素 - reverse()2、数组元素排序 - sort() 默认从小到大排序3、数组元素排序 - sort() 自定义排序规则4、数组元素排序 - sort() 自定义降序排序简化写法 Array 数组对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript…

C#编程模式之享元模式

创作背景&#xff1a;各位朋友&#xff0c;我们继续学习C#的编程模式&#xff0c;本文主要介绍享元模式。享元模式是一种结构型设计模式&#xff0c;它主要用于减少创建对象的数量&#xff0c;从而提高程序性能。它通过共享对象的方式来减少内存的使用&#xff0c;特别是系统中…

彩虹聚合DNS管理系统

聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&#xff0c;每个用户可分配不同的域名解析权限&#xff1b;支持API接口&#xff0c;支持获取域名…

同城组局同城活动找搭子小程序JAVA源码面芽组局的实现方案

功能概述 基于微信小程序开发的一款软件&#xff0c;支持用户动态发布、私信聊天关注、礼物充值打赏、发起活动组局、用户报名参与、支持商家入驻&#xff0c;对接广告功能等。 活动发布&#xff1a;用户可以在平台上发布各种类型的活动&#xff0c;如户外徒步、音乐会观赏、…

回炉重造java----单列集合(List,Set)

体系结构: 集合主要分为两种&#xff0c;单列集合collection和双列集合Map&#xff0c;区别在于单列集合一次插入一条数据&#xff0c;而双列的一次插入类似于key-value的形式 单列集合collection 注:红色的表示是接口&#xff0c;蓝色的是实现类 ①操作功能: 增加: add()&am…

探索震坤行API:一键解锁高效工业用品采购新纪元!

震坤行是一家专注于工业用品的B2B电商平台&#xff0c;为企业客户提供一站式的工业用品采购服务。虽然震坤行没有直接公开通用的API接口供开发者调用&#xff0c;但通常大型企业或合作伙伴之间可以通过API进行系统集成和数据交互。以下是一个假设性的震坤行API接口调用示例与代…

博特激光:355nm高精度紫外激光打标机带来极致工艺

紫外激光打标机在现代制造业和技术中的应用&#xff0c;的确在准确度和精密度方面带来了革命性的提高。特别是在微电子、半导体、医疗器械、高端消费品等需要高精度、高清晰打标的行业&#xff0c;紫外激光打标机以其独特的优势&#xff0c;赋予产品极致的工艺品质。 以下是UV激…

软件测试之 接口测试 Postman使用

接口测试 URL HTTP协议 HTTP 请求部分 HTTP响应部分 Postman使用 界面介绍 这里 注意 如果你无法访问 那么 captchaImage这个打错了&#xff0c;给的资料中是错误的地址 https://kdtx-test.itheima.net/api/captchaImage登录接口 科大天下 第一个接口的登录设置 https://kd…

基于vgg16和efficientnet卷积神经网络的天气识别系统(pytorch框架)全网首发【图像识别-天气分类】

一个能够从给定的环境图像中自动识别并分类天气&#xff08;如晴天、多云、雨天、雪天等&#xff09;的系统。 技术栈&#xff1a; 深度学习框架&#xff1a;PyTorch基础模型&#xff1a;VGG16与EfficientNet任务类型&#xff1a;计算机视觉中的图像分类 模型选择 VGG16 VGG…

Redis 源码安装(CentOS 单机)

序言 本文给大家介绍如何在 CentOS 上&#xff0c;通过 Redis 源码单机部署 Redis 服务。 一、部署流程 通过官网下载源码 # 下载源码 wget https://download.redis.io/redis-stable.tar.gz# 解压源码包 tar -xzvf redis-stable.tar.gz在 linux 中执行以下命令&#xff0c;安…

信息系统项目管理师0101:项目建议与立项申请(7项目立项管理—7.1项目建议与立项申请)

点击查看专栏目录 文章目录 第七章 项目立项管理7.1项目建议与立项申请1.立项申请概念2.项目建议书内容记忆要点总结第七章 项目立项管理 项目立项管理是对拟规划和实施的项目技术上的先进性、适用性,经济上的合理性、效益性,实施上的可能性、风险性以及社会价值的有效性、可…

Java面试——MyBatis

优质博文&#xff1a;IT-BLOG-CN 一、MyBatis 与 JDBC 的区别 【1】JDBC 是 Java 提供操作数据库的 API&#xff1b;MyBatis 是一个持久层 ORM 框架&#xff0c;底层是对 JDBC 的封装。 【2】使用 JDBC 需要连接数据库&#xff0c;注册驱动和数据库信息工作量大&#xff0c;每…

Html生成自定义函数的图形(2024/5/10)

大概效果如下&#xff1a; 可以自定义函数和x的定义域。 我们可以使用数学表达式解析库来解析用户输入的函数方程&#xff0c;并根据给定的 x 区间计算函数的值&#xff0c;然后使用图表库绘制图形。 在这里&#xff0c;我将使用 math.js 库来解析数学表达式&#xff0c;并使…

linux fdisk 银河麒麟操作系统 v10 磁盘分区和挂载 详细教程

1查看 未加载的磁盘 fdisk -l 2 开始分区 fdisk /dev/vdb #查看分区 #新建分区和保存 3 格式化和挂载 fdisk -l mkfs.xfs /dev/vdb1 #查看uuid blkid /dev/vdb1 mkdir /data vi /etc/fstab UUID209daa-fb1c-48f2-bf5e-e63f38cb8a /data xfs defaults 0 0 #加载下 mo…

Java 各类注解、Bean、作用域、生命周期

这里写目录标题 一、注解和Bean创建时机1. Controller:2.RestController:3.Service:4.Repository:5.Component: 二、作用域1.Singleton:2.Prototype:3.Request:4.Session: 一、注解和Bean创建时机 1. Controller: Bean生成时机: 在应用程序启动时由Spring容器创建。作用域: 默…