当前位置: 首页 > news >正文

C++中的模板(初阶)

C++中的模板是一项核心特性,它不仅支撑着vector等容器的实现,更是泛型编程、高阶迭代器设计以及仿函数开发的关键技术。今天,我们将深入解析模板这一重要概念

目录

1.泛型编程

2.函数模板

2.1函数模板的概念

2.3函数模板的原理

2.4函数模板的实例化

2.5函数模板的匹配原则

3.类模板

3.1类模板的定义格式

3.2类模板的实例化


如何实现一个通用的交换函数?

第一种方法就是用函数重载,一个个来实现

void Swap(int& a, int& b) { a = a + b; b = a - b; a = a - b; } void Swap(double& a, double& b) { a = a + b; b = a - b; a = a - b; } // ...

虽然函数重载可以实现这一功能,但不同重载函数仅参数类型不同,导致代码复用率较低。每当出现新类型时,用户都需要手动添加对应的重载函数

此外,代码的可维护性较差,一旦出现错误可能导致所有重载功能同时失效。

那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?

如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉

这也叫做泛型编程(编写与类型无关的通用代码,是代码复用的一种手段)模板就是泛型编程的基础

模板被分为函数模板和类模板

2.函数模板

2.1函数模板的概念

函数模板定义了一组功能相似的函数,其实现与具体类型无关。使用时通过参数化方式,编译器会根据传入的实际参数类型自动生成对应的特定类型函数版本。

2.2函数模板的格式

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

返回值类型 函数名(参数列表)

{}

就比如实现上面的交换函数:

template<typename T> void swap(T& a, T& b) { T tmp = a; a = b; b = tmp; }

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

2.3函数模板的原理

函数模板本质上是一个蓝图,它本身并非具体函数,而是编译器用来生成特定类型函数的模具。简而言之,模板的作用就是将原本需要手动完成的重复性工作交由编译器自动处理。

在编译阶段,编译器会根据模板函数调用时传入的实参类型进行类型推导生成对应的具体函数实现。例如,当使用double类型参数调用模板函数时,编译器会推导出T为double类型,并生成专门处理double类型的代码。对于其他数据类型,编译器也会采用相同的处理方式。

2.4函数模板的实例化

用不同类型的参数使用函数模板时,称为函数模板的实例化

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

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

template<class T> T Add(const T& a, const T& b) { return a + b; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, a2); Add(d1, d2); return 0; }

像这种情况就能够让编译器自主成功的推导参数类型

但是像下面这种情况就不能了

template<class T> T Add(const T& a, const T& b) { return a + b; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, d1); return 0; }

由于函数模板Add中只有一个T,所以编译器无法确定T是int,还是double类型

这是有两种方法解决:

1.我们自己强制转化

template<class T> T Add(const T& a, const T& b) { return a + b; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add(a1, (int)d1);// 将d1强转为int类型 return 0; }

2.显式实例化

template<class T> T Add(const T& a, const T& b) { return a + b; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add<int>(a1, d1); return 0; }

显式实例化:在函数名后加<>并指定其中模板参数的实际类型

如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错

2.5函数模板的匹配原则

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

template<class T> T Add(const T& a, const T& b) { return a + b; } int Add(const int& a, const int& b) { return a + b; } int main() { int a1 = 10, a2 = 20; double d1 = 10.0, d2 = 20.0; Add<int>(a1, a2);// 使用函数模板 Add(a1, a2);// 使用非模板函数 return 0; }

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

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

3.类模板

3.1类模板的定义格式

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

class 类模板名

{

// 类内成员定义

}

以类模板实现顺序表为例:

template<class T> class Seqlist { Seqlist(const size_t& capacity = 4) { _capacity = capacity; _array = new T[_capacity]; _size = 0; } // ... private: T* _array; size_t_size; size_t_capacity; };

3.2类模板的实例化

与函数模板实例化不同,类模板的实例化必须用显式实例化

template<class T> class Seqlist { Seqlist(const int& capacity = 4) { _capacity = capacity; array = new T[_capacity]; _size = 0; } // ... private: T* _array; int _size; int _capacity; }; int main() { Seqlist<int> sl;// 显式实例化 return 0; }

类模板名字不是真正的类,而实例化的结果才是真正的类

Seqlist是类名, Seqlist<int> 才是类型

注:模板的声明与定义不建议分离到不同的文件中,会发生链接错误

好了,以上就是模板(初阶)的全部内容了,感谢阅读,希望能够帮到你,也欢迎大家指错及补充

http://www.jsqmd.com/news/807988/

相关文章:

  • 硬件电路中的 EMC 设计
  • 数据库事务的四大特性以及事务并发访问引起的更新丢失问题
  • 西门子“工业软件驱动的数字孪生”模式
  • mac80211基础知识总结
  • HoRain云--PHP邮件发送终极指南
  • 快装管道售后服务测评? - 中媒介
  • 5分钟快速上手:res-downloader 全网资源下载神器终极指南
  • 告别固定尺寸:手把手教你用MATLAB Coder生成能处理任意大小数组的C函数
  • # 2026公考机构红黑榜!粉笔稳居第一,华图中公厮杀太激烈
  • RNN案例之:人名分类器
  • 2026年常州热缩管源头厂家深度横评:新能源汽车线束防护与工业级高分子材料定制解决方案 - 优质企业观察收录
  • 从‘Asia/Shanghai’到‘UTC’:一份给Python开发者的时区数据清洗与转换手册
  • 2026重庆靠谱装修公司测评:从施工、报价到售后,业主真实反馈 - 大渝测评
  • 广州市白蚁防治中心|越秀区/天河区/荔湾区/海珠区/白云区/番禺区专业灭白蚁公司推荐 - 品牌推荐大师
  • ComfyUI全面掌握-知识点详解——Comfy Cloud 部署与使用(注册、导航与对比)
  • 量子反馈电路中的动态相变与测量诱导纠缠研究
  • 智能车牌识别系统:YOLOv5+LPRNet深度学习引擎,车辆信息库+性能监控!
  • 【Flutter for open harmony 】Flutter三方库Dio网络请求+熬夜记录列表的鸿蒙化适配与实战指南
  • 1.ADC(采样和转换时间、常规单通道转换、定时器触发、串口示波器)
  • 从理论到实践:LMS自适应波束形成算法在干扰抑制中的实战解析
  • pyton笔记
  • 【Mem0】 源码剖析(一):Agent 的记忆危机与 Mem0 的三阶段管道——为什么 RAG 不够用?
  • AIoT 技术难点
  • 基于OpenAI API与社交平台集成的智能聊天机器人构建指南
  • 【架构实战】从业务逻辑到工程落地:私教预约系统的三大核心模型解析
  • 上海学瑜伽普拉提,2026年这篇看完就够了 - 速递信息
  • 手把手调试USB设备连接失败:Reset信号相关的常见坑与排查指南
  • ARMv8虚拟化中的HSTR_EL2寄存器原理与应用
  • 为什么 DISTINCT 加了 ROWNUM 反而数据变少了?揭秘 KES 与 PG 的执行优先级陷阱
  • 从热传导到细胞轨迹:一个公式讲明白Diffusion Map的数学直觉