模板初阶(泛型编程)

news2025/7/13 14:39:51

在这里插入图片描述

模板初阶

  • 🔆泛型编程
  • 🔆函数模板
    • 函数模板概念
    • 函数模板格式
    • 函数模板的原理
    • 函数模板的实例化
    • 模板参数的匹配原则
  • 🔆类模板
    • 类模板的定义格式
    • 类模板的实例化
    • 类模板与模板类的区别
  • 🔆结语

🔆泛型编程

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
在这里插入图片描述

🔆函数模板

函数模板概念

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

函数模板格式

emplate typename<T1,…,typename Tn>
返回值类型 函数名(参数列表){}

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

【注意】:typename是用来定义模板参数的关键字,也可以使用class(但是不能用struct代替)

函数模板的原理

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

函数模板的实例化

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

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

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

int main() {
	int a = 1;
	int b = 2;
	float c = 3.3f;
	float d = 4.4f;

	Add(a, b);
	Add(c, d);


	//Add(a, c);  //这里编译器会报错,模板参数只有一个,而这里有两种类型的实参,编译器无法确定此处该转换为哪种类型,编译报错
	//解决办法:1.强制转换;2.显示实例化
	Add(a, (int)c);
	Add<int>(a, c);

	return 0;
}

2.显示实例化:在调用函数时,在函数名后的<>中指定模板参数的实际类型。

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

int main() {
	int a = 1;
	double b = 6.6;

	Add<double>(a,b);
	return 0;
}

模板参数的匹配原则

1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

int Add(const int& a, const int& b) {
	cout << "int Add(const int& a, const int& b)" << endl;
	return a + b;
}

template<typename T>
T Add(const T& a, const T& b) {
	cout << "T Add(const T& a, const T& b)" << endl;
	return a + b;
}

int main() {
	Add(1, 2);  //与非模板函数匹配,编译器不需要转换
	Add<int>(1, 2);  //调用编译器使用函数模板生成的Add
	return 0;
}

在这里插入图片描述

2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

int Add(const int& a, const int& b) {
	cout << "int Add(const int& a, const int& b)" << endl;
	return a + b;
}

template<typename T1, typename T2>
T1 Add(const T1& a, const T2& b) {
	cout << "T1 Add(const T1& a, const T2& b)" << endl;
	return a + b;
}

int main() {
	Add(1, 2);   //编译器调用非函数模板的同名函数
	Add(1, 2.0); //函数模板可以实例化出更匹配的版本,编译器根据实参生成更加匹配的Add函数
	return 0;
}

在这里插入图片描述

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

//这个函数可以自动类型转换
int Add(const int& a, const int& b) {
	cout << "int Add(const int& a, const int& b)" << endl;
	return a + b;
}

//这个函数模板实例化不出来类型不同的函数,不可以自动类型转换
//template<typename T>
//T Add(const T& a, const T& b) {
//	cout << "T1 Add(const T1& a, const T2& b)" << endl;
//	return a + b;
//}

int main() {
	Add(1, 2.0);
	return 0;
}

🔆类模板

类模板的定义格式

template<class T1, ......, class Tn>
class {
	//类内成员的定义
};
template<class T>
class Stack{
public:
	Stack(const int capacity = 4);
	~Stack();
private:
	T* _a;
	int _top;
	int _capacity;
	static int _b;
};

template<class T>
int Stack<T>::_b = 0;

//注意类模板在类外定义成员函数时,需要加模板参数列表
template<class T>
Stack<T>::Stack(const int capacity)
	:_a(new T[4]{ 0 })
	,_top(-1)
	,_capacity(capacity)
{}

template<class T>
Stack<T>::~Stack() {
	delete[] _a;
	_top = -1;
	_capacity = 0;
}

类模板的实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类.

template<class T>
class Stack{
public:
	Stack(const int capacity = 4);
	~Stack();
private:
	T* _a;
	int _top;
	int _capacity;
	static int _b;
};

template<class T>
int Stack<T>::_b = 0;

//注意类模板在类外定义成员函数时,需要加模板参数列表
template<class T>
Stack<T>::Stack(const int capacity)
	:_a(new T[4]{ 0 })
	,_top(-1)
	,_capacity(capacity)
{}

template<class T>
Stack<T>::~Stack() {
	delete[] _a;
	_top = -1;
	_capacity = 0;
}

int main() {
	//Stack是类名,Stack<int>才是s的类型
	Stack<int> s;
	return 0;
}

类模板与模板类的区别

类模板:主要描述的是模板,这个模板是类的模板。可以理解为一个通用的类,这个类中的数据成员,成员函数的形参类型以及成员函数的返回值类型不用具体的指定,这些类型都是虚拟的。在使用类模板进行对象定义的时候,才会根据对象的实际参数类型来替代类模板中的虚拟类型。通俗一点来说,可以看作是做蛋糕的模具。
模板类:主要描述的是类,这个类使用类模板进行声明。将类模板中的虚拟类型参数指定成一个具体的数据类型参数。通俗一点来说可以看作是通过蛋糕模具做出来的蛋糕。

int main() {
	//Stack是模板类
	//s是模板类
	Stack<int> s;
	return 0;
}

🔆结语

到这里这篇博客已经结束啦。
这份博客👍如果对你有帮助,给博主一个免费的点赞以示鼓励欢迎各位🔎点赞👍评论收藏⭐️,谢谢!!!
如果有什么疑问或不同的见解,欢迎评论区留言欧👀

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

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

相关文章

【总结】Numpy2

Numpy 1. 数组和数的运算 array1 np.arange(1,10) array1 # array([1, 2, 3, 4, 5, 6, 7, 8, 9]) array1 10 # array([11, 12, 13, 14, 15, 16, 17, 18, 19]) array1 - 10 # array([-9, -8, -7, -6, -5, -4, -3, -2, -1]) array1 * 10 # array([10, 20, 30, 40, 50, 60, 70…

Flutter:如何在Android中实现串口通信调试

本文介绍如何通过flutter_libserialport插件在Flutter中实现串口通信调试。 1、引入依赖 在flutter工程的pubspec.yaml文件中引入flutter_libserialport依赖&#xff1a; dependencies:flutter_libserialport: ^0.3.0 2、导入import依赖包 在dart代码中import导入flutter_li…

快手国际化 后端开发面经二面

目录 1.Redis用的什么数据类型2.Hash底层结构3.JVM垃圾判别阶段算法4.MySQL索引模型5.为什么用B树6.联合索引在B树如何构造的7.覆盖索引知道吗 1.Redis用的什么数据类型 1.String(字符类型) 2.Hash(散列类型) 3.List(列表类型) 4.Set(集合类型) 5.SortedSet(有序集合类型&…

设计模式 单例模式(创建型)

一、前言 学习设计模式我们关注的是什么&#xff0c;如何实现么&#xff1f;是也不是。我认为比了解如何实现设计模式更重要的是这些设计模式的应用场景&#xff0c;什么场景下我们该用这种设计模式&#xff1b;以及这些设计模式所包含的思想&#xff0c;最终帮助我们把代码写…

继承 + 多态 + final + 权限修饰符

目录 继承 多态 final 权限修饰符 继承 继承定义&#xff1a; 可以让类跟类之间产生子父的关系继承的好处 可以把多个子类中重复的代码抽取到父类中&#xff0c;子类可以直接使用&#xff0c;减少代码几余&#xff0c;提高代码的复用性子类继承内容 非私有private构造方法…

#机器学习--深度学习中的正则化

#机器学习--深度学习中的正则化 引言1、参数范数惩罚2、 L 2 L^{2} L2 正则化3、 L 1 L^{1} L1 正则化4、显式约束和重投影5、参数绑定和参数共享6、Bagging7、Dropout 引言 本系列博客旨在为机器学习(深度学习)提供数学理论基础。因此内容更为精简&#xff0c;适合二次学习的…

uniapp实现条码扫描 可开闪光灯,原生H5调用,不需要任何sdk。

主要思路 使用QuaggaJs这个库。调用摄像头使用的 navigator.mediaDevices.getUserMedia 这个H5的api。通过 video 和 canvas 把摄像头获取到的数据展现到页面上&#xff0c;同时调用监听Quagga解析。 获取设备摄像头权限,用于后续开启摄像头。创建video元素显示摄像头画面,和ca…

AcWing算法提高课-1.3.10混合背包问题

宣传一下算法提高课整理 <— CSDN个人主页&#xff1a;更好的阅读体验 <— 本题链接&#xff08;AcWing&#xff09; 点这里 题目描述 有 N N N 种物品和一个容量是 V V V 的背包。 物品一共有三类&#xff1a; 第一类物品只能用1次&#xff08;01背包&#xff0…

opencv相机标定

当你把摄像机放在一个特定的位置&#xff0c;在它的后面放一个目标图像&#xff0c;或者是把摄像机放到某个物体上&#xff0c;摄像机周围的物体是什么形状&#xff0c;你需要知道这些信息。 当你在计算机上处理图像时&#xff0c;会使用以下三个参数&#xff1a; 1.像素坐标&a…

软件测试5年了,薪资25K,我还怕00后卷吗?

前言 沅哥在这个行业爬摸滚打5年了&#xff0c;从最开始点点点的功能测试到现在到现在成为高级测试&#xff0c;工资也翻了几倍&#xff0c;到了25k。他和我说&#xff0c;最开始他是想躺平的&#xff0c;后来也是被迫卷的&#xff0c;但好在这个结果他很满意。 之所以改变的…

一文3000字从0到1使用Selenium进行自动化测试

对于很多刚入门的测试新手来说&#xff0c;大家都将自动化测试作为自己职业发展的一个主要阶段。可是&#xff0c;在成为一名合格的自动化测试工程师之前&#xff0c;我们不仅要掌握相应的理论知识&#xff0c;还要进行大量的实践&#xff0c;积累足够的经验&#xff0c;以便快…

【重新定义matlab强大系列七】利用matlab函数ischange查找数据变化点

&#x1f517; 运行环境&#xff1a;matlab &#x1f6a9; 撰写作者&#xff1a;左手の明天 &#x1f947; 精选专栏&#xff1a;《python》 &#x1f525; 推荐专栏&#xff1a;《算法研究》 #### 防伪水印——左手の明天 #### &#x1f497; 大家好&#x1f917;&#x1f91…

为了入职字节测试岗准备半年,上岸拿个30K应该不算高吧?

历时近半年的面试终于告一段落&#xff0c;终于有时间整理下自己这次的换工作心得&#xff0c;分享给大家。 面试经历 我的基本情况是这样&#xff1a;中下等 985 学校本科毕业&#xff0c;非计算机专业&#xff0c;在北京工作五年&#xff0c;之前一直在中小私企、国企工作。…

程序语言易错题

程序语言易错题 包含8个成员的开发小组的沟通路径最多有&#xff08;&#xff09;条。 A、28 B、32 C、56 D、64 解析 软件开发小组的沟通路径受到小组组织形式和规模的影响。若任意小组成员之间均可能有沟通路径&#xff0c;则可用完全连通图来对开发小组的沟通路径建模&#…

Anaconda-labelimg的使用

文章目录 一、创建Anaco的虚拟环境并激活二、下载labelimg以及使用1.下载2.使用 在这里我是创建了一个虚拟环境&#xff0c;虚拟环境名字为labelimg 之后将labelimg下载到该虚拟环境中 一、创建Anaco的虚拟环境并激活 conda create -n labelimg conda activate labelimg二、下…

Smoothieware_best-for-pnp 工具链的升级尝试

文章目录 Smoothieware_best-for-pnp 工具链的升级尝试概述实验工具链安装的思路更换工具链的工作备注END Smoothieware_best-for-pnp 工具链的升级尝试 概述 正在迁移Smoothieware_best-for-pnp到MCUXPresso的失败实验中徘徊. 现在已知2者的工具链版本是不一样的. 通过2进制…

MAC免密登录服务器

文章目录 1.Mac本机打开终端生成公私钥2.找打刚才生成的公钥3.上传公钥到远程 Linux 服务器4.远程登录到Linux系统服务器里面执行如下操作5.设置后在退出终端,输入如下命令即可免密登录6. 禁止 Linux 使用账号密码登录 1.Mac本机打开终端生成公私钥 输入ssh-keygen&#xff0c…

python获取某电商平台口红数据并制作词云

目录标题 前言开发环境:模块使用数据来源分析代码展示获取数据制作词云 尾语 &#x1f49d; 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 开发环境: Python 3.8 Pycharm 模块使用 requests jieba 结巴分词 wordcloud 词云 第三方模块安装&#xff1a; win R 输…

Apache Kafka - 重识Kafka

文章目录 概述一、Kafka的概念二、Kafka的特点三、Kafka的使用场景导图 概述 Kafka是一个高性能、分布式的消息队列系统&#xff0c;它的出现为大规模的数据处理提供了一种可靠、快速的解决方案。我们先初步了解Kafka的概念、特点和使用场景。 一、Kafka的概念 Kafka是由Apac…

《设计模式》状态模式

《设计模式》状态模式 定义&#xff1a; 状态模式也称为状态机模式&#xff0c;允许对象在内部状态发生改变时改变它的行为&#xff0c;对象看起来好像修改了它的类。属于行为型模式。 状态模式的角色组成&#xff1a; State(抽象状态类)&#xff1a;定义一个接口用来封装与…