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

C++:模板

一.初识泛型编程

不难看出以上代码存在的问题:
 1. 重复冗余:针对 int 、 double 、 char 类型,交换逻辑完全一致,却要编写多份函数,增加代码量与维护成本,违背“避免重复”的编程原则 。
2. 扩展性差:若后续需支持新类型(如 string 等),必须再编写对应的重载函数,无法灵活适配新增类型,可维护性低 。
3. 未体现泛型优势:未借助C++模板机制简化代码,仍依赖手动编写重载,没能发挥泛型编程提升代码复用性、通用性的价值 。

    就以上问题C++,提出来泛型编程与模板的概念。

C++ 里的泛型编程,简单说就是 用“模板”当“万能模具” ,让一套代码能处理不同类型数据 。

你可以把模板想成做月饼的模具,不管要做豆沙馅、蛋黄馅月饼(对应不同数据类型,像  int 、 double  ),用同一个模具(模板)就行,不用为每种馅重新做模具。

写代码时,用  template  定义模板,里面用  T (或其他名字)当“类型占位符” 。比如写交换函数,不用给  int  、 double  分别写,搞个模板函数,让编译器根据传入的数据,自动把  T  换成对应类型,生成专属代码。

这样做能 少写重复代码 (一套逻辑适配所有类型),还能 保证类型安全 (编译器会检查类型对不对),像 STL 里的  vector 、 map  这些容器,底层就靠泛型模板实现,不管存  int  还是  string  ,都用同一套框架,特方便!

模板分为以下两类:函数模板和类模板

 

 

 

二.函数模板

1.函数模板定义

C++函数模板是泛型工具,用“模板参数”适配多种类型,一套逻辑处理不同数据,省重复代码。

 以上 C++ 函数模板定义。用  template<typename T>  声明, T  是类型参数,代表任意类型。定义  Swap  函数时,用  T  适配不同类型,调用时编译器依据实参自动推导  T  具体类型,生成对应函数,实现一套代码处理多种类型交换,体现泛型编程复用性。

  (注:处理使用typename关机自定义模板参数,还可以用class定义模板参数,但不能用struct定义)

 

2.函数模板的原理

函数模板相当于一个模具,本身并不是函数。

以上是 C++ 函数模板的类型推导与实例化流程示意:
1. 调用触发推导: main  里调用  Swap(d1,d2) ( double  类型)、 Swap(i1,i2) ( int  类型)、 Swap(a,b) ( char  类型)时,编译器会根据实参类型推导  T  。
2. 生成专属函数:推导后,编译器为每种类型自动生成对应函数(如  double  版  Swap  用  double  替换  T  , int  版同理 ),实现“一套模板、多份实例”,既复用逻辑,又保证类型适配,体现泛型编程的灵活与高效。

 

3.函数模板的实例化

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

 

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

 以上这段代码完美体现了 C++ 函数模板的隐式实例化,核心流程可以拆成三步理解:

 1. 模板是“蓝图”: template<typename T> void Swap(T& a, T& b)  是模板, T  是“类型占位符”,本身不是真正能运行的函数,更像一套“逻辑蓝图”。

2. 调用触发推导: main  里调用  Swap(a, b)  时,传入的  a  和  b  是  int  类型。编译器会自动推导:“哦,这里的  T  应该是  int  ”

3. 隐式生成函数:编译器悄悄帮你干了件大事 —— 根据推导结果,生成专门处理  int  类型的  Swap  函数(相当于自动写了  void Swap(int& a, int& b) { ... }  )。这个过程完全“隐式”,你不用手动写  Swap<int>(a, b)  ,编译器默默把模板变成了能运行的具体函数。

简单说,隐式实例化就是编译器根据你传的参数类型,自动把模板“变成”对应类型的实际函数,让你写代码时不用操心类型匹配,既复用逻辑,又写得轻松。

(2)显式实例化

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

 以上这段代码里的  Swap<int>(a, b) 、 Swap<double>(x, y)  就是 显式实例化,关键看这两点:
 
1. 手动指定类型:你在调用时,通过  <int> 、 <double>  直接告诉编译器:“用  int / double  替换模板里的  T  !” 不像隐式实例化那样靠参数推导,这里是你主动指定类型。
2. 强制生成实例:编译器收到指令后,会专门为  int  和  double  类型生成对应的  Swap  函数(比如  Sw1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这


简单说,显式实例化就是你直接指定模板参数类型,让编译器精准生成对应版本的函数,适合需要明确控制类型,或提前生成特定实例的场景。

4.函数模板的匹配规则

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

 展示了 C++ 函数模板匹配规则的典型场景。当调用  Swap(a, b)  时,因存在普通  int  版  Swap  函数,优先匹配它;调用  Swap(x, y)  时,无对应普通函数,触发模板隐式实例化生成  double  版。体现普通函数优先、模板按需实例化的匹配逻辑,帮我们理解函数模板调用时的选择机制 。

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

 代码呈现 C++ 函数匹配的场景。存在模板  Add  与普通  int  版  Add ,调用时: Add(a,b)  因普通函数精准匹配优先调用; Add(a,x) 、 Add(x,y)  触发模板,编译器根据实参推导类型,实例化对应模板函数,体现函数匹配规则里普通函数优先、模板按需实例化的逻辑 。

 

三.类模板

1.类模板的定义格式

 

 以下从类模板定义格式与显式实例化角度,对代码进行讲解:

①类模板定义格式

代码中  template<class T> class stack  遵循 C++ 类模板标准定义规范。

-  template<class T>  :作为模板参数声明, class  (也可替换为  typename  )用于引入类型参数  T  , T  本质是“类型占位符”,可代表  int 、 double  等任意数据类型,为类适配不同数据场景提供基础 。

-  class stack  :基于  T  构建类的整体结构,类内私有成员(如指针  T* _arr  、整型  _top  和  _capacity  )、公有成员(构造函数  stack  、成员函数  push  声明 ),均借助  T  实现类型适配,使  stack  类能依据  T  的具体类型,处理对应数据的栈操作逻辑。

 

②显式实例化

在  main  函数中, stack<int> st1;  与  stack<double> st2;  属于类模板的显式实例化操作:

 - 实例化时,需手动通过  <int> 、 <double>  明确指定类型参数,向编译器传递指令:使用  int  、 double  类型替换类模板中  T  ,生成专门处理对应类型数据的栈类(即  stack<int>  用于存储与操作  int  类型数据, stack<double>  用于  double  类型 )。

- 类模板特性决定其无隐式实例化机制,必须由开发者显式指定类型,编译器才会依据模板定义,生成对应类型的具体类代码,以支撑程序运行。

 

简言之,类模板依托  template<class T>  搭建通用逻辑框架,使用阶段需通过显式指定类型(如  <int>  、 <double>  ) 完成实例化,生成适配特定数据类型的类,达成一套模板复用、适配多类型场景的效果 。

(注:代码中构造函数内  _arr  虽经  new T[capacity]  动态分配内存,但未完善内存释放等资源管理逻辑,实际应用易引发内存泄漏等问题,需补充析构函数等进行优化 。 )

http://www.xdnf.cn/news/13157.html

相关文章:

  • 无服务器架构的企业级应用深度解析:Serverless技术选型与成本模型
  • DMA:在不同内存空间建立目的地址的情况分析及后果
  • 解锁 Nginx Stream 代理—全面掌握 ngx_stream_proxy_module
  • echarts使用笔记
  • java容易被忽略的事情
  • docker 安装运行mysql8.4.4
  • ceph 查看 pg 迁移进度的脚本
  • Oracle SQL*Plus 配置上下翻页功能
  • 大数据零基础学习day1之环境准备和大数据初步理解
  • APP开发好后如何分发内测
  • uniapp+vue2+h5图片下载保存,微信浏览器、非微信浏览器
  • java8 通过方法引用 vo::setLevel将对象的 setter 方法作为参数传递
  • Linux日志管理和时间管理
  • Java多线程实现之Callable接口深度解析
  • PyTorch终极实战:从自定义层到模型部署全流程拆解​
  • 接口测试中缓存处理策略
  • Code Composer Studio快捷键
  • OkHttp 中实现断点续传 demo
  • 【数据结构】图论经典:Dijkstra最短路径算法精解与工程优化
  • 计算机毕业设计微信小程序题库系统 在线答题 题目分类 错题本管理 学习记录查询系统源码+论文+PPT+讲解 基于微信小程序的题库系统设计与实现
  • JavaScript 核心对象深度解析:Math、Date 与 String
  • qt3d自定义生成mesh图形
  • 深度学习小项目合集-视频介绍下自取
  • 计算机系统概述(4)
  • LocalDate类使用
  • 电脑扩展屏幕工具
  • 【完整源码】白泽题库系统:基于PyQt5的智能刷题与考试平台开发全解析
  • 群晖NAS是否有专业的安全防护措施?是否支持无密码登录?
  • Android第十七次面试总结(Java数据结构)
  • 在写外部FLASH的应用时发现一些问题,在这里分享一下我的想法