【C++】了解模板

这里是目录

  • 前言
  • 函数模板
  • 函数模板的实例化
  • 类模板

前言

如果我们要交换两个数字,那么我们就需要写一个Swap函数来进行交换,那如果我们要交换char类型的数据呢?那又要写一份Swap的函数重载,参数的两个类型是char,那我们还要交换double类型的数据呢?难道又要写一份Swap函数重载?如果在添加个自定义类型的交换呢?
模板的作用就是解决此类问题,模板的主要功能是实现通用

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

函数模板

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

基本用法:

template<typename T>
//这里的typename也可以换为class,一般情况下用typename居多
//也可以多参数
template<class T1, class T2>

实现一个交换函数模板:

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

template<typename T> //模板参数 一般命名为T TY TP
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a = 2, b = 1;double c = 2.2, d = 1.1;cout << "交换前->" << a << " " << b << endl;Swap(a, b);cout << "交换后->" << a << " " << b << endl;cout << "交换前->" << c << " " << d << endl;Swap(c, d);cout << "交换后->" << c << " " << d << endl;return 0;
}

运行效果:
在这里插入图片描述
可以看到已经完成了交换,但实际上他们调用的并不是同一个函数,在编译器上看他们确实是调用的同一个函数,但是如果查看汇编就能发现他们调用的是不同的函数

在这里插入图片描述

可以看到调用的函数地址不相同

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此

模板的实例化图解:
在这里插入图片描述
C++库中是有交换函数的,只不过库里的是小写,所以我们以后想要交换数据直接用库里的就好了
在这里插入图片描述
函数模板可以有多个参数

template<typename T1,typename T2>
void Func(const T1& x, const T2& y)
{cout << x << " " << y << endl;
}

函数模板可以做返回值

template<typename T1,typename T2>
T1 Func(const T1& x, const T2& y)
{cout << x << " " << y << endl;return x;
}

函数模板实例化生成具体函数
函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数

函数模板的实例化

模板的实例化有两种方式
一种是隐式实例化:让编译器根据实参推演模板参数的实际类型
还有一种是显式实例化:在函数名后的<>中指定模板参数的实际类型

template<typename T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a = 10;int b = 20;double c = 10.0;double d = 20.0;//编译器自动推导cout << Add(a, b) << endl;cout << Add(c, d) << endl;//但是下面这种场景如果让编译器自动推导就会出问题cout << Add(a, d) << endl;return 0;
}

左边的T是int右边的T是double,那到底是T推导成int还是double呢?
这时候编译器就会出现问题了

错误信息:
在这里插入图片描述
有两种方法可以解决这个问题
方法一:

cout << Add(a, (int)d) << endl;
cout << Add((double)a, d) << endl;

这样就不会出现推导歧义了

方法二:

//显式实例化,用指定类型实例化
cout << Add<int>(a, d) << endl;
cout << Add<double>(a, d) << endl;

大部分模板都不需要显式实例化,只有少数需要
比如:

template<typename T>
T* Alloc(int n)
{return new T[n];
}int main()
{//有些函数无法自动推导,只能显式实例化double* arr = Alloc<double>(10);return 0;
}

类模板

//类模板
template<typename T>
class Stack
{
public:Stack(size_t capacity = 3){_array = new T[capacity];_capacity = capacity;_size = 0;}private:T* _array;int _capacity;int _size;
};int main()
{Stack<int> s1;Stack<double> s2;Stack<char> s3;return 0;
}

有了类模板就可以实现一个栈存储多类型的需求

类模板的声明和定义分离和普通的类不同:

//类模板
template<typename T>
class Stack
{
public:Stack(size_t capacity = 3);private:T* _array;int _capacity;int _size;
};//普通类,类名和类型是一样的
//类模板,类名和类型不一样,
//类名是:Stack
//类型是:Stack<T>
//最好不要分离到两个文件
template<typename T>
Stack<T>::Stack(size_t capacity)
{_array = new T[capacity];_capacity = capacity;_size = 0;
}int main()
{//类模板实例化Stack<int> s1;Stack<double> s2;Stack<char> s3;return 0;
}

总结:

优点:

  1. 灵活性, 可重用性和可扩展性
  2. 可以大大减少开发时间,模板可以把用同一个算法去适用于不同类型数据,在编译时确定具体的数据类型
  3. 模版模拟多态要比C++类继承实现多态效率要高,无虚函数,无继承

缺点:

  1. 可读性不好,调试比较困难
  2. 模板的数据类型只能在编译时才能被确定
  3. 所有用基于模板算法的实现必须包含在整个设计的.h头文件中, 当工程比较大的时候, 编译时间较长

以上就是本篇文章的全部内容了,希望大家看完能有所收获

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

免费WordPress站群插件-批量管理站群的免费软件

WordPress站群插件&#xff1a;让文章管理如丝般顺滑 在众多网站建设工具中&#xff0c;WordPress一直以其简便易用、丰富的插件生态而备受青睐。对于站群管理者而言&#xff0c;如何高效地更新、发布和推送文章是一项不可忽视的任务。本文将专注分享一款WordPress站群插件&am…

Vue语音播报,不用安装任何包和插件,直接调用。

Vue语音播报功能可以通过使用浏览器提供的Web Speech API来实现。这个API允许你的应用程序通过浏览器朗读文本&#xff0c;不用安装任何包和插件&#xff0c;直接调用。以下是一个简单的介绍&#xff0c;演示如何在Vue中使用语音提示功能&#xff1a; 一、JS版本 <template…

陈年雷司令葡萄酒中的石油笔记

雷司令葡萄酒通常在年轻时食用&#xff0c;当它们酿造出果味和芳香的葡萄酒时&#xff0c;可能带有绿色或其他苹果、葡萄柚、桃子、醋栗、蜂蜜、玫瑰花或切绿草的香气&#xff0c;并且由于酸度高&#xff0c;通常味道清脆。 雷司令天然的高酸度和各种风味使其适合长时间老化&am…

【MySQL】视图:简化查询

文章目录 create view … as创建视图更改或删除视图drop view 删除视图replace关键字&#xff1a;更改视图 可更新视图with check option子句&#xff1a;防止行被删除视图的其他优点简化查询减小数据库设计改动的影响使用视图限制基础表访问 create view … as创建视图 把常用…

代码级接口测试与单元测试的区别

关于接口测试 接口测试是一个比较宽泛的概念, 近几年在国内受到很多企业和测试从业者的追捧, 尤其是上层的UI在取悦用户的过程中迭代更新加快, UI自动化维护成本急剧上升的时代, 大家便转向了绕过前端的接口层面进行测试. 但是很多人, 对接口测试的理解并不完整, 事实上, 我们…

回答关于模糊C均值聚类(FCM)的一些问题!FCM停止迭代的条件是什么,FCM中的隶属度起什么作用?

文章目录 一、模糊C均值聚类&#xff08;FCM&#xff09;中的隶属度是起什么作用二、FCM停止迭代的条件是什么 一、模糊C均值聚类&#xff08;FCM&#xff09;中的隶属度是起什么作用 表示样本点对各个聚类中心的隶属程度。隶属度取值范围是0-1之间,值越大表示样本点越可能属于…

Windows系列:windows server 2003 - 组策略部署软件

通过组策略为域内用户部署&#xff08;deploy&#xff09;软件&#xff0c;可分为指派&#xff08;assign&#xff09;和发布&#xff08;publish&#xff09;。 软件指派给用户&#xff1a;用户在域内登录后&#xff0c;被“通告 advertised”给用户&#xff0c;此时仅安装了部…

nvm 下载node时候下载不到npm包的解决方法

个人博客链接 公众号-nvm 下载node时候下载不到npm包的解决方法 求关注 可以跳过的背景 最近项目比较有空&#xff0c;所以就可以有时间写一些demo&#xff0c;主要测试下react的一些语法&#xff0c;毕竟自己上次写react已经是22年的7月份了,期间对于react-router等的hook…

E云管家微信群聊机器人开发

请求URL&#xff1a; http://域名地址/modifyGroupRemark 请求方式&#xff1a; POST 请求头Headers&#xff1a; Content-Type&#xff1a;application/jsonAuthorization&#xff1a;login接口返回 参数&#xff1a; 参数名必选类型说明wId是String登录实例标识chatRo…

11月30日作业

作业&#xff1a; 设计一个Per类&#xff0c;类中包含私有成员:姓名、年龄、指针成员身高、体重&#xff0c;再设计一个Stu类&#xff0c;类中包含私有成员:成绩、Per类对象p1&#xff0c;设计这两个类的构造函数、析构函数和拷贝构造函数。 #include <iostream>using n…

13-Vue基础之自定义指令与插槽的使用

个人名片&#xff1a; &#x1f60a;作者简介&#xff1a;一名大二在校生 &#x1f921; 个人主页&#xff1a;坠入暮云间x &#x1f43c;座右铭&#xff1a;懒惰受到的惩罚不仅仅是自己的失败&#xff0c;还有别人的成功。 &#x1f385;**学习目标: 坚持每一次的学习打卡 文章…

Electron+Ts+Vue+Vite桌面应用系列:TypeScript常用时间处理工具

文章目录 1️⃣ 时间处理工具1.1 格式化时间1.2 把时间戳改成日期格式1.3 Day.js 工具类使用1.4 date-fns 工具类使用 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/134712978 ElectronTsVueVite桌面应用…