C++之初识模版

news2025/1/23 22:26:41

目录

1.关于模版的介绍

2.函数模版

2.1函数模板概念

2.2函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5模板参数的匹配原则

3.类模版

3.1类模板的定义格式

3.2 类模板的实例化


1.关于模版的介绍

  • C++中的模板是一种通用编程工具,它允许程序员编写具有通用性的函数或类,可以适用于不同类型的数据。模板使用泛型编程的概念,即代码可以处理多种不同的数据类型,而不只是特定的类型。
  • 在C++中,有两种类型的模板:函数模板和类模板。                 
  • --->函数模板是一种通用的函数定义,可以用于处理不同类型的参数。函数模板使用一对尖括号 "<>" 包围一个或多个类型参数,这些类型参数在函数定义中可以用作函数参数或返回类型的占位符。在调用函数模板时,编译器会根据实际参数的类型来推导出模板参数的具体类型。
  • --->类模板是一种通用的类定义,可以用于创建具有相同结构但可能使用不同类型的成员的类。类模板的定义使用一对尖括号 "<>" 包围一个或多个类型参数,这些类型参数在类定义中可以用作类的成员变量、成员函数的参数或返回类型的占位符。在实例化类模板时,需要提供实际类型的参数。
  • 使用模板可以提供代码的重用性和灵活性,因为它使得编写可以用于处理不同类型数据的通用代码成为可能。模板还可以提供更好的类型检查,并在编译时进行错误检查。

2.函数模版

2.1函数模板概念

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

2.2函数模板格式

template<typename T1, typename T2,......,typename Tn>返回值类型 函数名(参数列表){}
演示:
template<typename T>//template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1, b = 0; double c = 3.1415925, d = 4.2526036;
	Swap(a, b); Swap(c, d);
	cout << a << b << c << d << endl;
	return 0;
}

2.3 函数模板的原理

    函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
    在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
演示:
template<typename T>//template<class T>
void Swap(T& a, T& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1, b = 0; 
	Swap(a, b); 
    double c = 3.1415925, d = 4.2526036;
	Swap(c, d);
	char e = 'a', f = 'b';
	Swap(e, f);
	return 0;
}

2.4 函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
演示:
template<typename T1,typename T2>//template<class T>
void Swap(T1& a, T2& b)
{
	T tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1, b = 0; 
    double c = 3.1415925, d = 4.2526036;
    Swap(a, b); 
	Swap(c, d);
	Swap(a, d);
	return 0;
}

这段代码可以成功运行吗?当然可以,因为我们用typename创建了两个模版参数T1和T2,传参时会发生隐式实例化,即便是a与d参数类型不同,也可以分别实例化,那如果将参数减少为一个呢?

// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}

这时候报错了,这是因为a是int类型,d是double类型,如果都交给同一个模版参数那么编译器就不知道要隐式实例化为int还是double类型,这时有两种解决办法:
  1. 将a强制类型转换为double或将d强制类型转换为int;
  2. 使用显式实例化
2. 显式实例化:在函数名后的<>中指定模板参数的实际类型
template<typename V>//template<class T>
void Swap(const V& a,const V& b)
{
	V tmp = a;
	a = b;
	b = tmp;
}
int main()
{
	int a = 1, b = 0; 
    double c = 3.1415925, d = 4.2526036;
	Swap<double>(a, d);
	return 0;
}

注意:这里只是演示显式实例化,交换函数在传参时会产生临时变量,具有常性,因此必须用const类型进行接收,不然权限就被放大了,但const修饰之后不可以更改值,因此还请读者注意!

2.5模板参数的匹配原则

1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
// 专门处理int的加法函数
int Add(int left, int right)
{
	return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add版本
}
2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
// 专门处理int的加法函数
int Add(int left, int right)
{
 return left + right;
}
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
 return left + right;
}
void Test()
{
 Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
 Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函
数
}
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3.类模版

3.1类模板的定义格式

形式:

template<class T1, class T2, ..., class Tn>
class 类模板名
{
 // 类内成员定义
};

演示:

template<class T>
class A
{
public:
	A(int year = 2025, int month = 1, int day = 19);
	~A()
	{}
private:
	T* arr;
	int _year;
	int _month;
	int _day;
};

template<class T>//作用域就是一个函数或者就是一个类,提取出来就要加上模板
A<T>::A(int year, int month , int day)//A是类名 A<T>是类型 要区分开来
{
	cout << year << "-" << month << "-" << day << endl;
	this->_year = year;
	this->_month = month;
	this->_day = day;
}

注意:

  1. 缺省参数只能在声明时候标注,在定义的时候标注会引发冲突;
  2. 一般在类中模版参数类型为class,而普通函数模版参数类型为typename;
  3. 类中函数在类外定义时,需要加上template...因为模版的作用域是一个类或者是一个函数,每当重新定义新的类或者函数,都需要重新加上模版
  4. 类外函数声明在用模版参数时不再是简单的类名::函数名,而需要在类名后加上<模版参数>,这是语法规定!

3.2 类模板的实例化

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

演示:
template<class T>
class A
{
public:
	A(int year = 2025, int month = 1, int day = 19);
	~A()
	{}
private:
	T* arr;
	int _year;
	int _month;
	int _day;
};
template<class T>//作用域就是一个函数或者就是一个类,提取出来就要加上模板
A<T>::A(int year, int month , int day)//A是类名 A<T>是类型 要区分开来
{
	cout << year << "-" << month << "-" << day << endl;
	this->_year = year;
	this->_month = month;
	this->_day = day;
}
int main()
{
	A<int> a1;
	A<double> a2;
	return 0;
}

在main函数中实例化一个类时,使用<>,中间填入模版类型即可~

补充:

  1. 模板的实参在任何时候都可以省略,模板实参省略意思为隐式实例化,一般情况下都使用隐式实例化,不需指定模板类型参数,让编译器进行推导,但有些情况下编译器推导时可能会有歧义,比如:模板参数只有一个类型T,但是用两个不同类型隐式实例化。

  2. 类模板与模板类所指的是同一概念,类模板是一个类家族,模板类是通过类模板实例化的具体类

  3. 类模板的参数可以是虚拟类型的,也可以是具体类型,C++中类模板的参数即为模板参数列表中内容,有两种方式:类型参数和非类型参数,类型参数:即类型参数化,将来实例化为具体的实际类型,有点像函数的形参,形参可以接受不同值的实参;非类型参数:在定义时给定了具体的类型,用该类型定义的为常量。

  4. 类模板中的成员函数全是模板函数,定义时都必须通过完整的模板语法进行定义。 因为所有类模板的成员函数,放在类外定义时,需要在函数名前加类名,而类名实际为ClassName<T>,所以定义时还需加模板参数列表。

- - - - - - ————————————本文结束———————————— - - - - - -

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

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

相关文章

题解 CodeForces 131D Subway BFS C++

题目传送门 Problem - 131D - Codeforceshttps://codeforces.com/problemset/problem/131/Dhttps://codeforces.com/problemset/problem/131/Dhttps://codeforces.com/problemset/problem/131/D 翻译 地铁方案&#xff0c;对于Berland城市来说是一种经典的表示&#xff0c;由…

【STM32】-TTP223B触摸开关

前言 本文章旨在记录博主STM32的学习经验&#xff0c;我自身也在不断的学习当中&#xff0c;如果文章有写的不对的地方&#xff0c;欢迎各位大佬批评指正。 准备工作 今天这篇文章介绍的是触摸开关这一外围硬件。 ST-link调试器STM32最小系统板单路TTP223B触摸传感器模块LE…

ceph基本概念,架构,部署(一)

一、分布式存储概述 1.存储分类 存储分为封闭系统的存储和开放系统的存储&#xff0c;而对于开放系统的存储又被分为内置存储和外挂存储。 外挂存储又被细分为直连式存储(DAS)和网络存储(FAS)&#xff0c;而网络存储又被细分网络接入存储(NAS)和存储区域网络(SAN)等。 DAS(D…

Apache Hive3定位表并更改其位置

Apache Hive3表 1、Apache Hive3表概述2、Hive3表存储格式3、Hive3事务表4、Hive3外部表5、定位Hive3表并更改位置6、使用点表示法引用表7、理解CREATE TABLE行为 1、Apache Hive3表概述 Apache Hive3表类型的定义和表类型与ACID属性的关系图使得Hive表变得清晰。表的位置取决于…

计算机网络介质访问控制全攻略:从信道划分到协议详解!!!

一、信道划分介质访问控制 介质访问控制&#xff1a;多个节点共享同一个“总线型”广播信道时&#xff0c;可能发生“信号冲突” 应该怎么控制各节点对传输介质的访问&#xff0c;才能减少冲突&#xff0c;甚至避免冲突? 时分复用(TDM) 时分复用&#xff1a;将时间分为等长的“…

IJCAI-2024 | 具身导航的花样Prompts!VLN-MP:利用多模态Prompts增强视觉语言导航能力

作者&#xff1a; Haodong Hong1,2 , Sen Wang1∗ , Zi Huang1 , Qi Wu3 and Jiajun Liu2,1 单位&#xff1a;昆士兰大学&#xff0c;澳大利亚科学与工业研究组织&#xff0c;阿德莱德大学 论文标题&#xff1a;Why Only Text: Empowering Vision-and-Language Navigation wi…

C语言程序设计十大排序—冒泡排序

文章目录 1.概念✅2.冒泡排序&#x1f388;3.代码实现✅3.1 直接写✨3.2 函数✨ 4.总结✅ 1.概念✅ 排序是数据处理的基本操作之一&#xff0c;每次算法竞赛都很多题目用到排序。排序算法是计算机科学中基础且常用的算法&#xff0c;排序后的数据更易于处理和查找。在计算机发展…

docker 安装 redis 详解

在平常的开发工作中&#xff0c;我们经常会用到 redis&#xff0c;那么 docker 下应该如何安装 redis 呢&#xff1f;简单来说&#xff1a;第一步&#xff1a;拉取redis镜像&#xff1b;第二步&#xff1a;设置 redis.conf 配置文件&#xff1b;第三步&#xff1a;编写 docker-…

人工智能之深度学习_[4]-神经网络入门

文章目录 神经网络基础1 神经网络1.1 神经网络概念1.1.1 什么是神经网络1.1.2 如何构建神经网络1.1.3 神经网络内部状态值和激活值 1.2 激活函数1.2.1 网络非线性因素理解1.2.2 常见激活函数1.2.2.1 Sigmoid 激活函数1.2.2.2 Tanh 激活函数1.2.2.3 ReLU 激活函数1.2.2.4 SoftMa…

FPGA中场战事

2023年10月3日,英特尔宣布由桑德拉里维拉(Sandra Rivera)担任“分拆”后独立运营的可编程事业部首席执行官。 从数据中心和人工智能(DCAI)部门总经理,转身为执掌该业务的CEO,对她取得像AMD掌门人苏姿丰博士类似的成功,无疑抱以厚望。 十年前,英特尔花费167亿美元真金白银…

李沐vscode配置+github管理+FFmpeg视频搬运+百度API添加翻译字幕

终端输入nvidia-smi查看cuda版本 我的是12.5&#xff0c;在网上没有找到12.5的torch&#xff0c;就安装12.1的。torch&#xff0c;torchvision&#xff0c;torchaudio版本以及python版本要对应 参考&#xff1a;https://blog.csdn.net/FengHanI/article/details/135116114 创…

Android系统开发(六):从Linux到Android:模块化开发,GKI内核的硬核科普

引言&#xff1a; 今天我们聊聊Android生态中最“硬核”的话题&#xff1a;通用内核镜像&#xff08;GKI&#xff09;与内核模块接口&#xff08;KMI&#xff09;。这是内核碎片化终结者的秘密武器&#xff0c;解决了内核和供应商模块之间无尽的兼容性问题。为什么重要&#x…

K8S如何让worker使用kubectl命令(RBAC方法)

背景 目前集群规划如下 kubeadm安装集群master节点默认能使用kubectl命令&#xff0c;worker则不能使用。这是因为worker节点没授权。当然&#xff0c;你可以通过以下方式授权 mkdir .kube scp master1:/root/.kube/config .kube/但这样无疑给了worker节点非常大的权限&#…

【Excel】【VBA】Reaction超限点筛选与散点图可视化

【Excel】【VBA】Reaction超限点筛选与散点图可视化 功能概述 这段代码实现了以下功能&#xff1a; 从SAFE输出的结果worksheet通过datalink获取更新数据从指定工作表中读取数据检测超过阈值的数据点生成结果表格并添加格式化创建可视化散点图显示执行时间 流程图 #mermaid-…

[Computer Vision]实验三:图像拼接

目录 一、实验内容 二、实验过程及结果 2.1 单应性变换 2.2 RANSAC算法 三、实验小结 一、实验内容 理解单应性变换中各种变换的原理&#xff08;自由度&#xff09;&#xff0c;并实现图像平移、旋转、仿射变换等操作&#xff0c;输出对应的单应性矩阵。利用RANSAC算法优…

微信小程序使用picker根据接口给的省市区的数据实现省市区三级联动或者省市区街道等多级联动

接口数据如上图 省市区多级联动&#xff0c;都是使用的一个接口通过传参父类的code。返回我们想要的数据 比如获取省就直接不要参数。市就把省得code传给接口&#xff0c;区就把市的code作为参数。 <picker mode"multiSelector" :range"mulSelect1" …

自动化01

测试用例的万能公式&#xff1a;功能测试界面测试性能测试易用性测试安全性测试兼容性测试 自动化的主要目的就是用来进行回归测试 新产品--第一个版本 (具备丰富的功能)&#xff0c;将产品的整体进行测试&#xff0c;人工创造一个自动化测试用例&#xff0c;在n个版本的时候…

JS宏进阶:正则表达式的使用

正则表达式&#xff0c;对于任何一门编程语言来说&#xff0c;都是一种非常强大的工具&#xff0c;主要用于搜索、编辑或操作文本和数据。因此&#xff0c;在JS中&#xff0c;也存在相应的对象new RegExp( )&#xff0c;在本章中&#xff0c;将详细介绍正则表达式在JS宏中的运用…

深度学习笔记——循环神经网络RNN

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本文详细介绍面试过程中可能遇到的循环神经网络RNN知识点。 文章目录 文本特征提取的方法1. 基础方法1.1 词袋模型&#xff08;Bag of Words, BOW&#xff09;工作原…

Git进阶笔记系列(01)Git核心架构原理 | 常用命令实战集合

读书笔记&#xff1a;卓越强迫症强大恐惧症&#xff0c;在亲子家庭、职场关系里尤其是纵向关系模型里&#xff0c;这两种状态很容易无缝衔接。尤其父母对子女、领导对下属&#xff0c;都有望子成龙、强将无弱兵的期望&#xff0c;然而在你的面前&#xff0c;他们才是永远强大的…