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++模板

1.内容引入

? 不知道大家是否在高中时背过英语范文模板,以下就是博主的回忆:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QNn4QUSM-1662721853348)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909164444041.png)]

? 这篇模板是一些英语比较好的老师写的。

? 每当碰到感谢信时,我都会狂喜,尽管感谢的内容不同,地点不同,我都可以去根据模板,再根据作文分析模板的那些空对应应该填入什么。

其实呢c++中也用模板,但是这个时候,我们是写模板的人,而编译器变成了那个根据模板照葫芦画瓢的人

2.模板函数

c语言写交换函数

#include<iostream>
using namespace std;

void Swapi(int* a, int* b)
{
	int tmp = *a;
	*a = *b;
	*b = tmp;
}

void Swapd(double* a, double* b)
{
	double tmp = *a;
	*a = *b;
	*b = tmp;
}

//……

int main()
{
	int a = 1, b = 2;
	Swapi(&a, &b);
	double c = 1.1, d = 2.2;
	Swapd(&c, &d);

	return 0;
}

? 要实现不同类型的交换,实参不仅要传地址,而且不同类型的函数的名字要保持不同

至于为什么会这样,大家可以去看看我的文章。解释了为什么c语言不支持函数重载:

(196条消息) C++入门语法之函数重载与引用的再度解析_龟龟不断向前的博客-CSDN博客


C++写交换函数

#include<iostream>
using namespace std;

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

void Swap(double& x, double& y)
{
	double tmp = x;
	x = y;
	y = tmp;
}

//……

int main()
{
	int a = 1, b = 2;
	Swap(a, b);

	double c = 1.1, d = 2.2;
	Swap(c, d);
	return 0;
}

? C++在语法上增加了引用和函数重载,在一定程度上弥补了c语言的不足,但是上述代码明明逻辑很相似,却还是要我们去实现不同类型的代码,对于我们这种懒人来说,简直就是煎熬,连我马云爸爸也说过懒人创造世界。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GH6dYuwx-1662721853352)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909170100833.png)]

? 但是计算机他是一个任劳任怨的好铁,不来不会感到疲劳,厌倦,是一个头脑优点笨笨的但是计算能力超强的大铁块。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n8sbDawb-1662721853355)(D:\gitee仓库\博客使用的表情包\玩电脑.jpg)]


模板交换函数的语法及其原理

语法
#include<iostream>
using namespace std;

template <class T>
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

int main()
{
	int a = 1, b = 2;
	Swap(a, b);

	double c = 1.1, d = 2.2;
	Swap(c, d);
	return 0;
}

? 这样写交换函数是不是就轻松多了,但是我们思考以下,上述代码调用的是一个Swap函数还是两个Swap函数呢

回顾我们说的模板,是我们写的模板,然后编译器照着模板帮我们写出了intdouble类型的交换函数。


原理

图解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5AIhvYQ7-1662721853358)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909171041891.png)]


我们也可以通过调试上述代码,转到反汇编,看看调用的函数是否真的是不同的函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEYJkyhC-1662721853360)(C:\Users\Cherish\AppData\Roaming\Typora\typora-user-images\image-20220909171157206.png)]


理解显示实例化和隐式实例化

我们那模板加法函数来理解

#include<iostream>
using namespace std;

T Add(const T& x,const T& y)
{
	return x + y;
}

int main()
{
	int a = 1, b = 2;
	double c = 1.1, d = 2.2;

	cout << Add(a, b) << endl;//编译器要自己推类型的是隐式实例化
	cout << Add(c, d) << endl;

	//cout << Add(a, c) << endl;//error这样的写法就错了,为难编译器了,编译器也推不出来了
	cout << Add<int>(a, c) << endl;//不需要编译器去推的是显示实例化
	cout << Add<double>(b, d) << endl;

	cout << Add(a, (int)c) << endl;
	return 0;
}

编译器要自己去推T是什么类型的,就是隐式实例化

而由我们告诉编译器T是什么类型的,就是显示实例化


关于编译器也是懒人这件事

我们来看几道模板函数的代码来看看编译器是如何做事的:

#include<iostream>
using namespace std;

int Add(int left, int right)
{
	return left + right;
}

// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}

int main()
{
	Add(1, 2);       // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2);  // 调用编译器特化的Add版本
	return 0;
}

? 如果调试了上述代码就会发现,编译器第一次调用的是第一个Add函数,第二次由于我们的指定,编译器调用的是模板加法函数。


#include<iostream>
using namespace std;

int Add(int left, int right)
{
	return left + right;
}

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

int main()
{
	Add(1, 2);
	Add(1, 2.0);//如果不写模板,会进行一个类型转换,再去调用第一个
	return 0;
}

3.类模板

由于c++的顺序表是用vector表示的,下面咱们的类名也用vector表示

像以前我们实现一个顺序表是这样的。

typedef int VDateType;
class vector
{
public:
	//……
private:
	VDateType* _a;
	size_t _size;
	size_t _capacity;
};

int main()
{
	vector v1;
	vector v2;
	return 0;
}

但是我们无法让v1是int类型的顺序表,v2是double类型的顺序表。


用模板类来实现

#include<iostream>
#include<assert.h>
using namespace std;

namespace kcc
{
	template<class T>
	class vector
	{
	public:
		vector()
			:_a(nullptr)
			, _size(0)
			, _capacity(0)
		{}

		// 拷贝构造和operator= 这里涉及深浅拷贝问题,还挺复杂,后面具体再讲

		~vector()
		{
			delete[] _a;
			_a = nullptr;
			_size = _capacity = 0;
		}

		void push_back(const T& x)
		{
			if (_size == _capacity)
			{
				int newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				T* tmp = new T[newcapacity];
				if (_a)
				{
					memcpy(tmp, _a, sizeof(T) * _size);
					delete[] _a;
				}
				_a = tmp;
				_capacity = newcapacity;
			}

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

		// 读+写
		T& operator[](size_t pos);
		size_t size();
	private:
		T* _a;
		size_t _size;
		size_t _capacity;
	};

	// 模板不支持分离编译,也就是声明在.h ,定义在.cpp,原因后面再讲
	// 建议就是定义在一个文件 xxx.h  xxx.hpp
	// 在类外面定义
	template<class T>
	T& vector<T>::operator[](size_t pos)
	{
		assert(pos < _size);

		return _a[pos];
	}

	template<class T>
	size_t vector<T>::size()
	{
		return _size;
	}
}

int main()
{
	kcc::vector<int> v1;		// int
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	v1.push_back(4);

	// v1.operator[](3);
	//cout << v1[3] << endl;
	//cout << v1[5] << endl;
	for (size_t i = 0; i < v1.size(); ++i)
	{
		v1[i] *= 2;
	}
	cout << endl;

	for (size_t i = 0; i < v1.size(); ++i)
	{
		cout << v1[i] << " ";
	}
	cout << endl;


	kcc::vector<double> v2;   // double
	v2.push_back(1.1);
	v2.push_back(2.2);
	v2.push_back(3.3);
	v2.push_back(4.4);

	for (size_t i = 0; i < v2.size(); ++i)
	{
		cout << v2[i] << " ";
	}
	cout << endl;

	return 0;
}

如果内部成员函数在类的外面定义的话,要加上类名::

当然了,本文章并不是重点介绍顺序表vector的实现,而是让大家看看类模板的效果

vector会在后续的文章中更新,敬请期待!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OPoAfNMy-1662721853365)(D:\gitee仓库\博客使用的表情包\给点赞吧.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sRpdbA8n-1662721853367)(D:\gitee仓库\博客使用的表情包\要赞.jpg)]

感谢观看!

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 01:47:57  更:2022-09-15 01:48:21 
 
开发: 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/18 4:19:39-

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