模板(简单介绍C++)

news2024/11/18 17:51:45

模板

  • 引入模板
  • 函数模板
    • 概念
    • 语法
    • 函数模板的原理
    • 函数模板实列化
      • 隐式实例化
      • 显示实例化
    • 模板参数匹配原则
  • 类模板
    • 类模板的定义格式
    • 类模板的实列化
  • 泛型编程
    • 补充知识

引入模板

当我们想实现一个通用的交换函数时,我们能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成需要的代码?
答案:是可以的。

在没有学习模板之前,通过之前学习的知识,我们知道了函数重载。可以通过函数重载实现不同类型的相同功能的同名函数。函数重载

函数重载的缺点:

  1. 代码复用率低,只要有新的类型出现,就需要用户增加对应的函数。
  2. 可维护性低,一个出错可能所有的重载都出错。

函数模板

概念

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

语法

template<typename T1, typedef T2,…, typedef Tn> 或者 template<class T1, typedef T2,…, typedef Tn>
返回值类型 函数名(参数列表) {}

eg:

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

注意: typename是用来定义模板参数的关键字,也可以使用class。

函数模板的原理

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

编译器在编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。
类似对象实例化

函数模板实列化

概念:用不同类型的参数使用函数模板。

隐式实例化

让编译器根据实参推演模板参数的实际类型。

template<typename T>
//这const要加,因为下面实参被强制类型转化了
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	int a1 = 10, a2 = 20;
	double d1 = 10.1, d2 = 20.2;
	Add(a1, a2);
	Add(d1, d2);

	//因为模板参数列表就一个T,编译器无法确定T是int类型还是double类型
	//在模板中,编译器一般不会进行类型转换操作,因为如果转换出现问题,就是编译器的原因了
	//Add(a1, d1);   //err

	//两种处理方式:1.用户自己强转 2.使用显示实列化
	Add(a1, (int)d1);
	Add((double)a1, d1);

	return 0;
}

有写函数无法自动推,只能显示实列化。
eg:

template<class T>
T* Alloc(int n)
{
	return new T[n];
}

int main()
{
	//只能显示实列化
	double* p1 = Alloc<double>(10);
	//double* p1 = Alloc(10);   //err
	return 0;
}

显示实例化

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

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

int main()
{
	int a = 10;
	double b = 20.1;

	//显示实列化
	Add<int>(a, b);  //b 隐式类型转换
	return 0;
}

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

模板参数匹配原则

  1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
    eg:
int Add(int left, int right)
{
	return left + right;
}

template<class T>
T Add(T left, T right)
{
	return left + right;
}

int main()
{
	Add(1, 2);        //与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2);   //调用编译器特化的Add版本
	return 0;
}
  1. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
    eg:
int Add(int left, int right)
{
	return left + right;
}

template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
	return left + right;
}

int main()
{
	Add(1, 2);        //与非模板函数类型完全匹配,不需要函数模板实列化
	Add(1, 2.0);      //模板函数可以生成更加匹配的版本
	return 0;
}
  1. 在 C++ 中,模板函数不会自动进行类型转换,而普通函数会。
    eg:
template <typename T>
void templateFunction(T value) {
    std::cout << "Template function: " << value << std::endl;
}
void normalFunction(int value) {
    std::cout << "Normal function: " << value << std::endl;
}

int main() {
    int intValue = 10;
    double doubleValue = 3.14;

    templateFunction(intValue);  // 不会进行类型转换,输出:Template function: 10
    templateFunction(doubleValue);  // 不会进行类型转换,输出:Template function: 3.14

    normalFunction(intValue);  // 进行了隐式类型转换,输出:Normal function: 10
    normalFunction(doubleValue);  // 进行了隐式类型转换,输出:Normal function: 3

    return 0;
}

在上述代码中,

  1. templateFunction是一个模板函数,它可以接受任意类型的参数。无论传入的参数是int还是double,都不会进行类型转换,而是直接使用传入的参数类型。
  2. 而normalFunction是一个普通函数,它的参数类型是int。当我们传入一个double类型的参数时,编译器会自动进行隐式类型转换,将doubleValue的值转换成int类型,然后调用该函数。

因此,模板函数不允许自动类型转换,而普通函数可以进行自动类型转换。

类模板

类模板的定义格式

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

这里就不写个类的模板介绍了,后续的stl容器博客会有相关模板内容

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

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

类模板的实列化

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

eg:

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

泛型编程

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。
模板是泛型编程的基础

补充知识

  1. 模板最重要的一点就是类型无关,提高代码复用率
  2. 模板运行时不检查数据类型,也不保证类型安全,相当于类型的宏替换
  3. 只要支持模板语法,模板的代码就是可移植的。
  4. 模板的实参,在参数类型不同时,有时需要展示指定的类型参数
  5. 类模板是一个类家族,模板类是通过模板实列化的具体类。
  6. 类模板的虚拟类型是指类模板在使用时的占位类型
  7. 类模板的成员函数,全是模板函数。

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

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

相关文章

基于Java+SpringBoot+vue前后端分离墙绘产品展示交易平台设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Ansible 自动化运维

目录 ansible 环境安装部署ansible 命令行模块inventory 主机清单 Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;现在也在自动化管理领域大放异彩。它融合了众多老牌运维工具的优点&#xff0c;Pubbet和Saltstack能实现的功能&#xff0c;Ansible基本上都可…

MySQL 之 Buffer Pool

一、innoDB设计缓冲池目的 避免频繁访问磁盘&#xff0c;提高数据库读写性能。&#xff08;作用与引用Cache三级缓存类似。&#xff09; 二、缓冲池工作模式 读取数据&#xff1a;当Buffer Pool存在目标数据&#xff0c;就直接返回给客户端&#xff0c;没有再磁盘取数据。 修改…

1-高性能计算研究

高性能计算研究 E级计算机系统研制高性能计算应用软件研发并行编程框架应用协同开发优化平台和工具软件示例 高性能计算环境研发 E级计算机系统研制 高性能互联计算、编程、运行模型 应用驱动的新型可扩展基础算法&#xff08;适用于E级计算的可计算物理建模与新型计算方法&a…

softmax回归

模型 softmax回归是多类分类模型&#xff0c;用于获取每个分类的置信度&#xff0c;置信度计算方式如下 经过全连接层&#xff0c;得到输出O&#xff0c;将O作为softmax的输入 O是输出向量&#xff0c;每个分量表示一个类别&#xff0c;y_hat_i表示i类别的置信度&#xff0…

[语义分割] DeepLab v1网络(语义分割、信号下采样、空间上的不敏感性、LargeFOV、膨胀卷积、空洞卷积、MSc、Multi-Scale)

Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs 论文地址&#xff1a;Semantic Image Segmentation with Deep Convolutional Nets and Fully Connected CRFs参考源码&#xff1a;https://github.com/TheLegendAli/DeepLab-Context DeepL…

数据库中的Hash索引以及哈希碰撞

hash索引&#xff0c;就是用过一定的hash算法&#xff0c;将键值换算成新的hash值&#xff0c;映射到对应的槽位上&#xff0c;然后存储在hash表中 就比如下面的name字段&#xff0c;经过算法的分析&#xff0c;就会对应出一张hash表 如果我的两个name字段计算出来的key相同&a…

vscode eslint配置

1. 全局安装 eslint npm install -g eslint 2. control shift p 输入 settings 打开设置进行配置 3. 添加配置 {"workbench.colorTheme": "One Dark Pro","eslint.debug": true,"eslint.execArgv": null,"eslint.alwaysShow…

多表关联查询

十七、多表关联查询 但是开发中不会使用联合主键&#xff0c;还是只会使用一个主键 多表关联查询&#xff1a; 建表&#xff1a; 交叉连接 …… …… 重复时写清楚是哪个表的&#xff0c;不然会报错&#xff1a; 2、内连接 王妍没有部门&#xff0c;查不出来。此时需要用到外连…

Python 进阶(一):PyCharm 下载、安装和使用

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 一、下载 PyCharm二、安装 PyCharm三、创建项目四、界面汉化五、实用技巧5.1、使用快捷…

SpringMvc+Mybatis完整项目

0目录 1.SpringmybatisSpringmvc查询功能&#xff08;记录数&#xff09; 2.查询所有 3.增删改查&#xff08;根据id&#xff09; 4.增加用户注册登录功能 1.SpringmybatisSpringmvc增删改查 新建数据库 创建工程 配置web.xml 配置applicationContext.xml 实体类 My…

24考研数据结构-栈

目录 第三章 栈和队列3.1栈&#xff08;stack&#xff09;3.1.1栈的基本概念栈的基本概念知识回顾 3.1.2 栈的顺序存储上溢与下溢栈的顺序存储知识回顾 3.1.3栈的链式存储链栈的基本操作 第三章 栈和队列 3.1栈&#xff08;stack&#xff09; 3.1.1栈的基本概念 栈的定义 栈…

主流开源监控系统一览

减少故障有两个层面的意思&#xff0c;一个是做好常态预防&#xff0c;不让故障发生&#xff1b;另一个是如果故障发生&#xff0c;要能尽快止损&#xff0c;减少故障时长。而监控的典型作用&#xff0c;就是帮助我们发现及定位故障&#xff0c;这两个环节对于减少故障时长至关…

Docker挂载目录失败问题解决

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

SpringCloudAlibaba:服务网关之Gateway的cors跨域问题

目录 一&#xff1a;解决问题 二&#xff1a;什么是跨域 三&#xff1a;cors跨域是什么&#xff1f; 一&#xff1a;解决问题 遇到错误&#xff1a; 前端请求时报错 解决&#xff1a; 网关中添加配置文件&#xff0c;注意springboot版本&#xff0c;添加配置。 springboo…

Opencv Win10+Qt+Cmake 开发环境搭建

文章目录 一.Opencv安装二.Qt搭建opencv开发环境 一.Opencv安装 官网下载Opencv安装包 双击下载的软件进行解压 3. 系统环境变量添加 二.Qt搭建opencv开发环境 创建一个新的Qt项目(Non-Qt Project) 打开创建好的项目中的CMakeLists.txt&#xff0c;添加如下代码 # openc…

SpringBoot IOC与AOP(一)

IOC AOP 一、 分层解耦 内聚&#xff1a; 软件中各个功能模块内部的功能联系 耦合&#xff1a; 衡量软件中各个层/模块之间的依赖、关联的程度 软件设计原则&#xff1a;高内聚、低耦合 ​ 控制反转&#xff1a;Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到…

Java 悲观锁 乐观锁

锁可以从不同的角都分类。其中乐观锁和悲观锁是一种分类方式 一、悲观锁、乐观锁定义 悲观锁就是我们常说到的锁。对于悲观锁来说&#xff0c;他总是认为每次访问共享资源时会发生冲突&#xff0c;所以必须每次数据操作加上锁&#xff0c;以保证临界区的程序同一时间只能有一个…

文件上传漏洞 -- uploadlabs为例

文件上传漏洞原理 一些web应用程序中允许上传图片、视频、头像和许多其他类型的文件到服务器中。 文件上传漏洞就是利用服务端代码对文件上传路径变量过滤不严格将可执行的文件上传到一个到服务器中 &#xff0c;再通过URL去访问以执行恶意代码。 非法用户可以利用上传的恶意脚…

如何使用 Flatpak 在 Linux 上安装 ONLYOFFICE 桌面编辑器?

Flatpak 是一款与 Linux 发行版无关的软件实用工具&#xff0c;可用于在 Linux 上构建和分发桌面端应用。其可帮助您安装第三方 Linux 应用程序&#xff0c;无需安装库或处理依赖。 ONLYOFFICE 桌面版是什么 ONLYOFFICE 编辑器桌面版是一款全面的办公工具&#xff0c;提供了文…