IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 【C++】模板初阶 —— 泛型编程 -> 正文阅读

[C++知识库]【C++】模板初阶 —— 泛型编程

🌈欢迎来到C++专栏~~模板初阶


  • (???(??? )🐣,我是Scort🎓
  • 🌍博客主页:张小姐的猫~江湖背景
  • 快上车🚘,握好方向盘跟我有一起打天下嘞!
  • 送给自己的一句鸡汤🤔:
  • 🔥真正的大师永远怀着一颗学徒的心
  • 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏
  • 🎉🎉欢迎持续关注!
    在这里插入图片描述

请添加图片描述

请添加图片描述

一. 泛型编程

函数重载可以实现不同类型的交换函数——

void Swap(int& x1, int& x2)
{
	int tmp = x1;
	x1 = x2;
	x2 = tmp;
}

void Swap(double& x1, double& x2)
{
	int tmp = x1;
	x1 = x2;
	x2 = tmp;
}

int main()
{
	int i1 = 10, i2 = 20;
	double d1 = 1.1, d2 = 2.2;
	Swap(i1, i2);
	Swap(d1, d2);
	return 0;
}

但是有两个不好的地方:

  1. 代码的逻辑仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
  2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

在这里插入图片描述

🔥泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础
类比我们的活字印刷术

在这里插入图片描述

二. 函数模板

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

🌍函数模板格式

template后面类型名字T是随便取,Ty、K、V、一般是大写字母或者单词首字母大写
T 代表是一个模板类型(虚拟类型)

template<typename T1, typename T2,......,typename Tn>//模板参数(模板类型)
swap(参数列表)                                        //类似函数参数(对象)
{
   //.....
}

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

//template<class T>
template<typename T>
void Swap(T& left, T& right) 
{
	T temp = left;//这里最好不用异或,异或只使用整形int,那其他类型??
	left = right;
	right = temp;
}

🌍函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器根据传入的实参类型来推演生成对应类型的函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器(感慨,懒人创造世界啊)
在这里插入图片描述
转到反汇编,我们可以看到——调用的函数地址都不一样

在这里插入图片描述
注意这个和auto不一样

🌍函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化

1.🌊 隐式实例化:让编译器根据实参推演模板参数的实际类型

上述代码都是隐式实例化

看如下代码,该语句不能通过编译。因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a将T推演为int,通过实参d将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错

在这里插入图片描述

ps:模板函数不支持隐式类型转化

此时有两种处理方式:① 强制类型转换 ② 显式实例化

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	//强制类型转化 ———— 对自己先处理
	cout << Add((int)1, 2) << endl;
	cout << Add(1.1,(double) 2) << endl;
}

🔥显示实例化:在函数名后的<>指定模板参数的实际类型

#include<iostream>
using namespace std;

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	int a = 1;
	double d = 2.2;

	// 显式实例化 ————告诉编译器,指定了
	cout << Add<int>(a, d) << endl;
	cout << Add<double>(a, d) << endl;
	return 0;
}

🌍函数模板的匹配原则

一个非模板函数可以和一个同名的函数模板同时存在 ,如果其他条件都相同,在调动时会优先调用普通函数而不会从该模板产生出一个实例

在这里插入图片描述

如果模板可以产生一个具有更好匹配的函数, 那么优先选择模板

在这里插入图片描述💚:有现成的就用现成的,没有再套模板

ps:模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

三. 类模板

C语言没有数据结构,很大程度上是因为不支持泛型编程。虽然我们用typedef int DataType; 类型重命名,可以稍作改动来更改数据类型,但是如果在一个大型工程里,我们同时要用int栈char栈,只能勉强把相同逻辑的代码写两遍。C++有了类模板,编译器可以根据被实例化的类型生成真正的类

🎨类模板的定义格式

我们以栈为例——

template<class T>
class Stack
{
public:
	Stack(int capacity = 4)
		:_top(0)
		, _capacity(capacity)
	{
		_a = new T[_capacity];
	}

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

private:
	T* _a;
	int _top;
	int _capacity;
};

🎨类模板的实例化

类模板实例化与函数模板实例化不同,函数模板可以指定模板参数类型,也可以不指定,编译器会根据实参进行推演。但是类模板实例化只支持显示实例化,因为没法推演

	Stack<int> st1;	// 存储int
	Stack<char> st2;	// 存储char

注:这里Stack是类名,Stack<T>才是类型!

🍅:模板不支持分离编译,后续我们来谈 可以在当前文件声明和定义分离

//typedef int STDataType;
template<typename T>
class Stack
{
public:
	Stack(size_t capacity = 4)
		:_a(nullptr)
		,_capacity(0)
		,_top(0)
	{
		if (capacity > 0)
		{
			_a = new T[capacity];
			_capacity = capacity;
			_top = top;
		}
	}
	~Stack()
	{
		delete[] _a;
		_a = nullptr;
		_capacity = _top = 0;
	}

	void Push(const T& x);

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

private:
	T _a;
	size_t top;
	size_t capacity;
};

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<int> st1;
		//Stack<char> st1;

		st1.Push(1);
		st1.Push(2);
		st1.Push(3);
		st1.Push(4);
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

📢写在最后

  • 能看到这里的都是棒棒哒🙌!
  • 想必模板也算是C++中重要🔥的部分了,如果认真看完以上部分,肯定有所收获。
  • 接下来我还会继续写关于📚《SLT》等…
  • 💯如有错误可以尽管指出💯
  • 🥇想学吗?我教你啊🥇
  • 🎉🎉觉得博主写的还不错的可以`一键三连撒

在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 20:56:54  更:2022-10-22 21:01:03 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 2:48:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码