【C++】初识模板:函数模板和类模板

目录

一、模板函数

1、函数模板的概念

2、函数模板的格式

3、函数模板的原理

4、函数模板实例化

5、 模板参数的匹配原则

二、类模板 

1 、类模板的定义格式

2 、类模板的实例化

3、模板类示例


一、模板函数

1、函数模板的概念

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

2、函数模板的格式

模板函数通过在函数定义前使用关键字 “template” 和一个或多个模板参数来定义。模板参数可以是类型参数或非类型参数。类型参数是用于指定函数参数类型的通用标识符,非类型参数则是用于指定常量值或常量表达式。

下面是一个简单的模板函数示例:

template <class T>
T findMax(T a, T b) {return (a > b) ? a : b;
}

在上面的示例中,我们定义了一个名为 “findMax” 的模板函数。该函数接受两个类型相同的参数,并返回较大的那个参数。通过使用模板参数 “T”,我们可以在不同的上下文中使用相同的函数实现。

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

3、函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模 板就是将本来应该我们做的重复的事情交给了编译器

 在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。
 

4、函数模板实例化

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

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

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double d1 = 10.0, d2 = 20.0;Add(a1, a2);Add(d1, d2);/*该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅Add(a1, d1);*/// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化Add(a1, (int)d1);return 0;
}

 

【2】、显式实例化:在函数名后的 < > 中指定模板参数的实际类型

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 20;double d1 = 10.0, d2 = 20.0;//  使用显式实例化Add<int>(a1, d1);return 0;
}
【注意】:如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

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】、模板函数不允许自动类型转换,但普通函数可以进行自动类型转换


二、类模板 

1 、类模板的定义格式

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

2 、类模板的实例化

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

3、模板类示例

模板类的定义类似于模板函数,需要使用关键字 “template” 和一个或多个模板参数来定义。模板参数可以是类型参数或非类型参数。类型参数用于指定类中的数据类型,非类型参数用于指定常量值或常量表达式。

下面是一个简单的模板类示例:

template <class T>
class Stack {
private:T* data;int top;int capacity;public:Stack(int maxCapacity) {capacity = maxCapacity;data = new T[capacity];top = -1;}~Stack() {delete[] data;}void push(T element) {if (top == capacity - 1) {throw std::overflow_error("Stack is full");}data[++top] = element;}T pop() {if (top == -1) {throw std::underflow_error("Stack is empty");}return data[top--];}bool isEmpty() {return (top == -1);}int size() {return top + 1;}
};

在上面的示例中,我们定义了一个名为 “Stack” 的模板类。它是一个栈数据结构的实现,可以用于存储各种类型的数据。通过使用模板参数 “T”,我们可以在不同的上下文中使用相同的类定义来创建具有不同数据类型的栈对象。

使用模板类时,我们需要在创建对象时指定具体的模板参数类型。例如:

int main() {Stack<int> intStack(10);Stack<double> doubleStack(20);intStack.push(5);doubleStack.push(3.14);intStack.pop();doubleStack.pop();return 0;
}

在上面的示例中,我们分别使用了整数和浮点数作为模板参数类型来创建了两个栈对象。通过这种方式,我们可以在不同的上下文中使用相同的类实现,提高代码的复用性和灵活性。

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

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

相关文章

堆的概念实现

前言 本文将详细讲解堆。堆是一种二叉树&#xff08;一般是完全二叉树&#xff09;使用顺序结构的数组来存储。 tip&#xff1a;这里我们需要注意区分堆在不同地方的含义&#xff0c;这里的堆是一个数据结构&#xff0c;操作系统虚拟进程地址空间的堆是操作系统中管理内存的一块…

备战蓝桥杯---动态规划之背包问题引入

先看一个背包问题的简单版&#xff1a; 如果我们暴力枚举可能会超时。 但我们想一想&#xff0c;我们其实不关心怎么放&#xff0c;我们关心的是放后剩下的体积。 用可行性描述即可。 于是我们令f[i][j]表示前i个物品能否放满体积为j的背包。 f[i][j]f[i-1][j]||f[i-1][j-v…

怎么开启耳穴实操的道路

一.背景 前面的文章耳穴为什么有用&#xff1f;-CSDN博客&#xff0c;我说明了耳穴为什么有用、又是很安全的。 然后又告诉你了颈椎痛的耳穴配方用程序员的思维学习耳穴调理的第一个配方“颈椎病”-CSDN博客。 大胆放手去实操吧&#xff01; 二.工具用什么 1.耳穴贴 由一…

K210如何下载程序

一、打开资料包里提供的K-Flash程序烧录软件 二、选择串口 三、选择波特率 四、选择In-Chip&#xff0c;烧录到Flash芯片里面&#xff0c;重新上电还会运行程序 五、如果选择In - Memory&#xff0c;这次可以运行&#xff0c;但下次重新上电就不会保持这次的程序了。 六、选择固…

火星符号运算 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 已知火星人使用的运算符号为 #和$ 其与地球人的等价公式如下 x#y2*x3*y4 x$y3*xy2x y是无符号整数。地球人公式按照c语言规则进行计算。火星人公式中&#xff0…

leetcode:63.不同路径二

dp数组含义&#xff1a;由初始位置到最终位置路径个数 递推公式&#xff1a;如果没有障碍再进行递推公式 初始化&#xff1a;1.若起始位置和终止位置有障碍路径个数为0 2.dp[i][0] 1和dp[0][j] 1的for循环条件都需要加上一个and dp[i][0] 0和and dp[0][j] 0. 3.遍历顺序…

Vue-Vue3 集成编辑器功能

1、安装依赖 编辑器插件需要安装 wangeditor/editor 和 wangeditor/editor-for-vue 两个插件 npm install wangeditor/editor --savevue3运行如下命令安装 npm install wangeditor/editor-for-vuenext --savevue2运行如下命令安装 npm install wangeditor/editor-for-vue -…

【前端web入门第四天】01 复合选择器与伪类选择器

文章目录: 1. 复合选择器 1.1 后代选择器 1.2 子代选择器 1.3 并集选择器1.4 交集选择器(了解) 2.伪类选择器 2.1 伪类-文本2.2 伪类-超链接&#xff08;拓展) 1. 复合选择器 什么叫复合选择器? 由两个或多个基础选择器&#xff0c;通过不同的方式组合而成。 复合选择器的作…

Peter算法小课堂—枚举优化

哈哈哈&#xff0c;新年快乐&#xff01;这一次Peter将要给大家讲一讲轻松、摆烂的算法—枚举&#xff01;咋就是说呀&#xff0c;枚举这个玩意我语法就会了。但大家想想&#xff0c;咱们CSP考试时&#xff08;除了没过初赛的&#xff09;只给1秒&#xff0c;大家想想&#xff…

macOS Sonoma 14.3.1(23D60)发布

系统介绍 黑果魏叔2 月 9 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14.3.1 更新&#xff08;内部版本号&#xff1a;23D60&#xff09;&#xff0c;本次更新距离上次发布隔了 17 天。 魏叔 查询苹果官方更新日志&#xff0c;macOS Sonoma 14.3.1 修复内容和 …

二层交换机配置以太网通道

实验大纲 二层聚合端口配置 1.构建网络拓扑结构图 2.修改交换机名字 3.创建聚合组进入聚合接口模式 4.将端口绑定到聚合端口&#xff08;接口模式&#xff09; 5.聚合接口下端口配置&#xff08;聚合接口模式) 6.具体配置 7.验证端口通道1的状态 8.配置ip 9.测试连通…

Qt安装配置教程windows版(包括:Qt5.8.0版本,Qt5.12,Qt5.14版本下载安装教程)(亲测可行)

目录 Qt5.8.0版本安装教程Qt5.8.0版本下载安装 Qt5.12.2版本安装教程下载安装 Qt 5.14.2安装教程下载安装和创建项目 参考视频 QT为嵌入式系统提供了大量的库和可重用组件。 WPS Office&#xff0c;咪咕音乐&#xff0c;Linux桌面环境等都是QT开发的。 Qt5.8.0版本安装教程 Q…