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

C++:模板开端

目录

1.泛型编程

 2.函数模板

2.1函数模板概念

2.2函数模板格式

2.3函数模板的原理

 2.4函数模板的实例化

 2.5模板参数的匹配原则

3.类模板 

3.1类模板的定义格式

3.2类模板的实例化


欢迎

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;
}
......
使用函数重载虽然可以实现,但是有一下几个不好的地方:
1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
2. 代码的可维护性比较低,一个出错可能所有的重载均出错
那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 呢?
如果在 C++ 中,也能够存在这样一个 模具 ,通过给这个模具中 填充不同材料 ( 类型 ) ,来 获得不同
材料的铸件 ( 即生成具体类型的代码) ,那将会节省许多头发。巧的是前人早已将树栽好,我们只
需在此乘凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

 2.函数模板

2.1函数模板概念

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

2.2函数模板格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名 ( 参数列表 ){}
temlate<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& 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);Add(a1,d1);
/*
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有
一个T,
编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要
背黑锅
Add(a1, d1);
*/
// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
Add(a, (int)d);
return 0;
}
2. 显式实例化 :在函数名后的 <> 中指定模板参数的实际类型

 

int main(void)
{
int a = 10;
double b = 20.0;
// 显式实例化
Add<int>(a, b);
return 0;
}

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

 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 类模板名
{
// 类内成员定义
};
#include<iostream>
using namespace std;// 类模板
template<typename T>
class Stack
{
public:// 构造函数,初始化堆栈,默认为容量4Stack(size_t capacity = 4){_array = new T[capacity];  _capacity = capacity;      _size = 0;                 }// 入栈操作void Push(const T& data);private:T* _array;           // 存储栈元素的数组size_t _capacity;    // 栈的容量size_t _size;        // 栈中当前元素的数量
};// 模板函数的定义。模板函数的定义建议与声明在同一文件中,避免链接错误。
template<class T>
void Stack<T>::Push(const T& data)
{// 将数据推入栈中_array[_size] = data;++_size;  // 更新栈的大小
}int main()
{Stack<int> st1;    // 创建一个存储整数的栈Stack<double> st2; // 创建一个存储双精度浮点数的栈return 0;
}

3.2类模板的实例化

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

 

// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double

再见

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Python 全栈系列271 微服务踩坑记
  • 什么是 SMB 服务器以及它如何工作?
  • AI论文精读笔记-Generative Adversarial Nets(GAN)
  • YOLOv5改进 | 模块缝合 | C3 融合RFAConv和CBAM注意力机制 【二次融合 小白必备】
  • GANs-生成对抗网络
  • 第二期: 第二节 , 裸机编程 , gpio
  • 基于python+django+vue的鲜花商城系统
  • kafka mirror maker之实现两个kafka集群之间的数据同步
  • freeRTOS 任务的创建、挂起、恢复
  • 使用PyTorch进行图像风格迁移:基于VGG19实现
  • 多目标优化算法求解LSMOP(Large-Scale Multi-Objective Optimization Problem)测试集,MATLAB代码
  • Windows和Mac命令窗快速打开文件夹
  • vue 项目自适应 配置 px转rem 的插件postcss-pxtorem
  • 数据中台建设(六)—— 数据开发-提取数据价值
  • Java实现建造者模式和源码中的应用
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • JAVA SE 6 GC调优笔记
  • js递归,无限分级树形折叠菜单
  • Python - 闭包Closure
  • Redis学习笔记 - pipline(流水线、管道)
  • SpiderData 2019年2月23日 DApp数据排行榜
  • 阿里云Kubernetes容器服务上体验Knative
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 前端知识点整理(待续)
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 突破自己的技术思维
  • 学习ES6 变量的解构赋值
  • k8s使用glusterfs实现动态持久化存储
  • Spring Batch JSON 支持
  • 大数据全解:定义、价值及挑战
  • 曾刷新两项世界纪录,腾讯优图人脸检测算法 DSFD 正式开源 ...
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #《AI中文版》V3 第 1 章 概述
  • #QT(串口助手-界面)
  • (~_~)
  • (11)MSP430F5529 定时器B
  • (13)Latex:基于ΤΕΧ的自动排版系统——写论文必备
  • (2)nginx 安装、启停
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (8)Linux使用C语言读取proc/stat等cpu使用数据
  • (9)STL算法之逆转旋转
  • (C++17) std算法之执行策略 execution
  • (ISPRS,2023)深度语义-视觉对齐用于zero-shot遥感图像场景分类
  • (第61天)多租户架构(CDB/PDB)
  • (二)斐波那契Fabonacci函数
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (几何:六边形面积)编写程序,提示用户输入六边形的边长,然后显示它的面积。
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (图文详解)小程序AppID申请以及在Hbuilderx中运行