C++之 【模板初阶(函数模板与类模板)】

news2025/3/24 18:23:07

目录

1.泛型编程

2.模板

3函数模板

3.1函数模板的概念

3.2函数模板的格式

3.3函数模板的原理

3.4函数模板的实例化

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

3.4.2显示实例化:在函数名后的<>中指定模板参数的实际类型

3.4.3模板参数的匹配原则

4.类模板

4.1类模板的定义

4.2类模板的格式

4.3类模板的原理

4.3类模板的实例化


1.泛型编程

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

上述代码完成的是不同类型的变量间的交换操作

可,这看着就有些麻烦,难写,因为,有多少种类型就需要写多少个函数

即使可以ctrl+c/ctrl+v,但仍存在下列问题:

1. 重载的函数仅仅是类型不同,代码复用率比较低

只要有新类型出现时,就需要用户自己增加对应的函数 

2. 代码的可维护性比较低,一个出错可能所有的重载均出错

由此,泛型编程产生了:

通过类型参数(即类型是一个参数)来创建函数或数据结构,

使得同一套代码可以适用于多种数据类型的编程范式就叫做泛型编程

template<typename T>
void Swap(T& x1, T& x2)
{
	T temp = x1;
	x1 = x2;
	x2 = temp;
}

上述代码通过使用模板,将类型参数化,就可以实现多种类型的变量间的交换操作

模板是泛型编程的基础

2.模板

上述浇筑过程中存在一个模具,通过给这个模具中填充不同材料,可以获得不同材料的铸件

C++中的模板就可以被视为一个模具,不同类型可以视为不同材料

本文介绍模板的两种主要形式:函数模板与类模板

3函数模板

3.1函数模板的概念

函数模板是一个与具体数据类型无关通用函数定义

具体来说就是,函数模板代表了一个函数家族

该函数模板中的类型被参数化,编译器根据实参类型产生函数的特定类型版本

3.2函数模板的格式

// 模板参数列表
template<typename T1, typename T2,......,typename Tn>
// 函数模板定义
返回值类型 函数名(参数列表){}

template<typename T>
void Swap(T& x1, T& x2)
{
	T temp = x1;
	x1 = x2;
	x2 = temp;
}

第一行写的是模板参数列表

template定义模板的关键字,

typename定义模板参数的关键字,

也可以用class定义模板参数,但不能用struct,如下:

template<class T1, class T2,......,class Tn>

第二行开始写函数模板,此时根据需要,将类型参数化

3.3函数模板的原理

函数模板是一个蓝图,不是函数

它是编译器根据实参类型产生特定类型函数模具

所以其实模板就是将本来应该我们做的重复的事情交给了编译器

在编译器编译阶段:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此

3.4函数模板的实例化

编译器根据实参类型产生特定类型函数的过程就称为函数模板的实例化

简单来说,函数模板的实例化就是通过函数模板生成一个函数

函数模板实例化分为:隐式实例化和显式实例化

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

此时,确保实参类型一致即可

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

int main()
{
	int a = 1, b = 2;
	double c = 3.0, d = 4.0;
	Add(a, b);
	Add(c, d);
	return 0;
}

这时候,有两种办法:1.强制类型转化

这里需要注意:强制类型转化会产生临时变量,临时变量具有常性

此时参数列表就必须要用const修饰,否则编译不通过。

而最开始用const修饰的初心是防止数据被修改

2.显式实例化

3.4.2显示实例化:在函数名后的<>中指定模板参数的实际类型

	Add<int>(a, c);

3.4.3模板参数的匹配原则

1.一个非模板函数可以和一个同名的函数模板同时存在

而且该函数模板还可以被实例化为这个非模板函数

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

int Add(int& x1, int& x2)
{
	return x1 + x2;
}

这就是上面说的同时存在

int main()
{
	Add(1, 2);
    Add<int>(1, 2);
	return 0;
}

第一次调用的函数,与非模板函数匹配,直接调用非模板函数,编译器不需要特化

第二次调用的函数是编译器特化的Add版本

这就是上面说的实例化

2.对于非模板函数和同名函数模板的调用

如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模 板产生出一个实例

如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

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

第一次调用的函数,与非模板函数匹配,直接调用非模板函数,编译器不需要特化

第二次调用的函数是编译器特化的Add版本,因为此时才更加匹配

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

在这里,编译器无法推导出T的具体类型,不会自动转换a或者c的类型

除非显式指定或者强制类型转换,不然编译器会直接报错

Add<int>(a, c);
Add(a, (int)c);
void foo(double d) {}
foo(42);        // int→double隐式转换

普通函数就支持自动类型转换

模板函数是类型生成机制,而普通函数是类型匹配机制。模板在编译期"雕刻"类型,普通函数在运行时"适配"类型。这种设计使得模板既能保持类型安全,又能通过特化和重载提供灵活性,而普通函数则通过隐式转换维持编程的便利性                        --------文心一言

4.类模板

4.1类模板的定义

类模板是一个与具体数据类型无关通用类定义

具体来说就是,类模板代表了一个类家族

该类模板中的类型被参数化,编译器根据实参类型产生类的特定类型版本

4.2类模板的格式

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

第一行写的是模板参数列表

template定义模板的关键字,

typename定义模板参数的关键字,

也可以用class定义模板参数,但不能用struct,如下:

template<class T1, class T2,......,class Tn>

第二行开始写类模板,此时根据需要,将类型参数化

template <class T>
 Vector<T>::~Vector()
 {
    if(_pData)
        delete[] _pData;
    _size = _capacity = 0;
 }

 注意:类模板中函数放在类外进行定义时,需要加模板参数列表,同时指定类模板

4.3类模板的原理

类模板不是一个类,类模板的原理与函数模板的原理相同,

就是将本来应该我们做的重复的事情(识别参数类型)交给了编译器

4.3类模板的实例化

简单来说,类模板的实例化就是通过模板生成一个具有特定数据类型的类

 // Vector类名,Vector<int>才是类型
 Vector<int> s1;
 Vector<double> s2;

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

总结:

 对于普通类来说,类名(类模板名)与类型一致

对于模板类来说,类名就是类模板名,类型还需要指定参数列表

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

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

相关文章

在线教育网站项目第四步:deepseek骗我, WSL2不能创建两个独立的Ubuntu,但我们能实现实例互访及外部访问

一、说明 上一章折腾了半天&#xff0c;搞出不少问题&#xff0c;今天我们在deepseek的帮助下&#xff0c;完成多个独立ubuntu24.04实例的安装&#xff0c;并完成固定ip&#xff0c;实践证明&#xff0c;deepseek不靠谱&#xff0c;浪费我2个小时时间&#xff0c;我们将在下面实…

在刀刃上发力:如何精准把握计划关键节点

关键路径分析是项目管理中的一种重要方法&#xff0c;它通过在甘特图中识别出项目中最长、最关键的路径&#xff0c;来确定项目的最短完成时间。 关键路径上的任务都是项目成功的关键因素&#xff0c;任何延误都可能导致整个项目的延期。关键路径分析对于项目管理者来说至关重要…

组合总和||

1.给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 #include <bits/stdc.h> using namespace std; vector<vector<int>> result; vec…

OpenCV图像拼接(2)基于羽化(feathering)技术的图像融合算法拼接类cv::detail::FeatherBlender

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::FeatherBlender 是 OpenCV 中用于图像拼接的一个类&#xff0c;它属于 stitching 模块的一部分。这个类实现了基于羽化&#xff08;…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加导出数据功能示例9,TableView15_09带排序的导出表格示例

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 Deep…

spring boot 登入权限RBAC模式

首先准备好5张表 user_info表&#xff0c;用户的信息表 role表&#xff0c;角色表&#xff08;比如超级管理员、管理员、审核员、采购......&#xff09; 创建user_role表&#xff0c;user_info表&#xff0c;role表的中间表 注意了&#xff0c;role_id和user_id是 u…

调用API拿到的值——存储方式

1.响应结果示例&#xff1a; "purposeTagList":["稳中向好及进中提质"] 2.数据库中定义的 3.值的获取&#xff1a; F1 JsonNode purposeTagListNode dataNode.path("purposeTagList");if (purposeTagListNode.isArray()) {StringBuilder purp…

第一讲 | 解锁C++编程能力:基础语法解析

C入门基础 一、C的第一个程序二、命名空间三、C输入&输出四、缺省参数/默认参数五、函数重载六、引用1.引用的特性2.引用的使用引用做返回值场景 3.const引用只有指针和引用涉及权限放大、缩小的问题&#xff0c;普通变量没有 4.指针和引用的关系 七、inline八、nullptr 一…

C++ --- 多态

1 多态的概念 多态(polymorphism)的概念&#xff1a;通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运⾏时多 态(动态多态)&#xff0c;这⾥我们重点讲运⾏时多态&#xff0c;编译时多态(静态多态)和运⾏时多态(动态多态)。编译时 多态(静态多态)主要就是我…

HAL库中使用空闲中断+DMA接收数据,接收失败的问题

问题&#xff1a; 串口屏与单片机通过串口&#xff08;USART1&#xff09;进行通信&#xff0c;调试时发现问题&#xff0c;现象如下&#xff1a; 手动页面的几个文本&#xff0c;输入的数字不会显示出来&#xff0c;比如初始值为0&#xff0c;输入200&#xff0c;200会一闪而…

使用pycel将Excel移植到Python

1.适用需求 有些工作可能长期适用excel来进行公式计算&#xff0c;当需要把工作流程转换为可视化界面时&#xff0c;开发人员不懂专业逻辑&#xff0c;手动摸索公式很大可能出错&#xff0c;而且费时费力 2.可用工具及缺点 pandas 方便进行数据处理&#xff0c;支持各种格…

学习应用层

应用层概述 客户/服务器方式&#xff08;C/S&#xff09;和对等方式&#xff08;P2P&#xff09; 动态主机配置协议DHCP 客户/服务器方式 DHCP报文会被封装成为UDP用户数据报&#xff0c;DHCP服务器端口号是UDP67&#xff0c;用户是UDP68。 广播发送&#xff0c;是因为并不知道…

C/C++转换为字符串宏和字符串拼接宏的综合使用

本文内容参考: C/C++ 宏拼接和宏展开为字符串 - DoubleLi - 博客园 特此致谢! 1. 转换为字符串宏与字符串拼接宏 (1)转换为字符串宏 转换为字符串的宏为: #define STR(x) #x //转字符串 (2)字符串拼接宏 字符串拼接的宏为: #define CONCAT(x,y) x##y //拼接 2…

掌握新编程语言的秘诀:利用 AI 快速上手 Python、Go、Java 和 Rust

网罗开发 &#xff08;小红书、快手、视频号同名&#xff09; 大家好&#xff0c;我是 展菲&#xff0c;目前在上市企业从事人工智能项目研发管理工作&#xff0c;平时热衷于分享各种编程领域的软硬技能知识以及前沿技术&#xff0c;包括iOS、前端、Harmony OS、Java、Python等…

个人常用的chrome好用插件

chrome可以说是兼容性和实用性较高的浏览器 没有复杂的ui 沉重的广告 加上各种各样的浏览器插件 现在罗列一下个人常用的几款好用的插件 1. Adblock Plus 一款免费的广告拦截器&#xff0c;可以拦截大部分网站上的广告推荐&#xff0c;还你一个干净舒服的页面 以下为b站演示…

数据库设计-笔记2

1.介绍一下MySQL 历史与发展 MySQL 最初由瑞典的 MySQL AB 公司开发&#xff0c;于 1995 年正式发布。2008 年&#xff0c;MySQL AB 公司被 Sun Microsystems 收购&#xff0c;之后 Sun 又被甲骨文&#xff08;Oracle&#xff09;公司收购&#xff0c;MySQL 成为 Oracle 旗下…

损失函数理解(二)——交叉熵损失

损失函数的目的是为了定量描述不同模型&#xff08;例如神经网络模型和人脑模型&#xff09;的差异。 交叉熵&#xff0c;顾名思义&#xff0c;与熵有关&#xff0c;先把模型换成熵这么一个数值&#xff0c;然后用这个数值比较不同模型之间的差异。 为什么要做这一步转换&…

基于随机森林回归预测葡萄酒质量

基于随机森林回归预测葡萄酒质量 1.作者介绍2.随机森林算法与数据集介绍2.1定义2.2核心思想2.3主要步骤2.4数据集介绍 3.算法实现3.1数据加载与探索3.2数据可视化3.3数据预处理&#xff08;标准化、划分训练/测试集&#xff09;3.4模型训练与优化&#xff08;随机森林回归 超参…

【Qt】QWidget属性2

&#x1f3e0;个人主页&#xff1a;Yui_ &#x1f351;操作环境&#xff1a;Qt Creator &#x1f680;所属专栏&#xff1a;Qt 文章目录 1. windowOpacity属性2. cursor属性2.1 自定义光标 3. font属性4.tooltip属性5. focusPolicy属性6. 总结 由于QWidget的常见属性实在太多&a…

OpenGL ES ->乒乓缓冲,计算只用两个帧缓冲对象(Frame Buffer Object)+叠加多个滤镜作用后的Bitmap

乒乓缓冲核心思想 不使用乒乓缓冲&#xff0c;如果要每个滤镜作用下的绘制内容&#xff0c;也就是这个滤镜作用下的帧缓冲&#xff0c;需要创建一个Frame Buffer Object加上对应的Frame Buffer Object Texture使用乒乓缓冲&#xff0c;只用两个Frame Buffer Object加上对应的F…