C++--模板(template)详解—— 函数模板与类模板

目录

1.泛型编程

2.函数模板

2.1 函数模板概念

2.2 函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5 模板参数的匹配原则

3.类模板

3.1 类模板的定义格式

3.2 类模板的实例化


1.泛型编程

在C中如果让你写一个交换函数,应该怎么做呢?

//用于整型的交换
void Swap1(int* x, int* y)
{int* tmp = *x;*x = *y;*y = *tmp;
}//用于双精度浮点数的交换
void Swap2(double *x, double *y)
{double *tmp = *x;*x = *y;*y = *tmp;
}

在C中需要使用指针来完成对两个数的交换,而且函数名也必须不同

在C++中我们学习了引用加重载,现在我们使用C++来试一下

//用于整型的交换
void Swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}//用于双精度浮点数的交换
void Swap(double& x, double& y)
{double tmp = x;x = y;y = tmp;
}

可以看到学了重载和引用实现两个数的交换依旧很麻烦,参数类型不同必然需要我们写出不同的函数来实现x , y的交换,在C++中依靠重载引用实现这种操作,但是有很多不好的的地方

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数

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

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

就像活字印刷术和造纸术一样,我们可以依靠这两样东西在不同的纸上刻不同的内容,C++中的摸具就好比造纸术一样,每一张都是同一摸具制作出,但每一张纸都是不一样的内容

在二十多年前,我们C++的鼻祖引入了模板(template)这个概念,模板是C++语言重要组成之一

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

2.函数模板

2.1 函数模板概念

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

2.2 函数模板格式

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

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

{

        //函数体

}

template<typename T>void Swap(T& x, T& y)
{T temp = x;x = y;y = temp;
}int main()
{//函数模板实例化生成具体函数//函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数int a = 10, b = 12;Swap(a, b);cout << a << ' ' << b << '\n';double c = 10.10, d = 20.20;Swap(c, d);cout << c << ' ' << d << '\n';swap(c, d);return 0;
}

使用模板,我们只需要一个函数就能解决上面的问题

因为swap是很常用的类型所以库里面它帮你已经写好了,swap函数直接使用就可以了

int main()
{//函数模板实例化生成具体函数//函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数int a = 10, b = 12;swap(a, b);cout << a << ' ' << b << '\n';double c = 10.10, d = 20.20;swap(c, d);cout << c << ' ' << d << '\n';swap(c, d);return 0;
}

tips:

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()
{Add(1, 9); Add(2, 8);return 0;
}

tips:以下这段代码不会通过编译

int main()
{int a = 10;double b = 20.2;Add(a, b);return 0;
}

在编译器编译期间,在模板实例化的时候,编译器需要推理a和b的类型,编译器将a的类型推演为int,b为double,但是模板只有一个参数T,即:编译器无法推断T的类型为int还是double,所以报错

注意:

在模板中,编译器一般不会自动转换类型,因为一旦错了,编译器就需要背黑锅

这里有两种解决方式:

1.使用强制类型转换,将这两个参数的类型转换为同一个类型

例:Add(a, (int)b);

2.就是我们下面要将的显式实例化

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

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

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

使用场景:

template <class T>
T* Alloc(int n)
{return new T[n];
}int main()
{double* p1 = Alloc<double>(10);    return 0;
}

需要传递形参n来申请空间,这里就必须要使用显式实例化

2.5 模板参数的匹配原则

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

//非模板函数,int类型的Add加法函数
int Add(int x, int y)
{return x + y;
}template <typename T1,typename T2>//模板函数,通用类型Add加法函数
T Add(const T1& x, const T2& y)
{return x + y;
}int main()
{Add(10, 20); //调用int类型的Add加法函数,编译器不会去实例化Add<int>(10, 20); //调用通用类型的Add加法函数,编译器会去实例化return 0;
}

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

//非模板函数,int类型的Add加法函数
int Add(int x, int y)
{return x + y;
}template <typename T1, typename T2>//模板函数,通用类型Add加法函数
T Add(const T1& x, const T2& y)
{return x + y;
}int main()
{int a = 10, b = 20;Add(10, 20); //与非模板函数更加吻合,编译器会使用int Add函数Add(10, 20.0); //编译器会选择模板函数T Add,模板函数会根据需求生成更加匹配的Add函数return 0;
}

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

template<typename T>T Add(const T& x, const T& y)
{return x + y;
}int main()
{int sum = Add(10, 10.5);return 0;
}

编译器不会帮你自动类型转换,将10转换为10.0,或10.5转换为10

3.类模板

3.1 类模板的定义格式

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

class 类模板名

{

        // 类内成员定义

};

类成员函数声明和定义分离

template<class T>
class Date
{
public:Date();void Print();
private:int _year;int _month;int _day;
};//普通类:类名和类型一样
//类模板:类名和类型不一样
//类模板 类名:Date 类型:Date<T>  (类型是类名加<模板参数(不用加class或typename)>)template<class T>
Date<T>::Date():_year(1),_month(1),day(1)
{}template<class T>
void Date<T>::Print()
{cout << _year << endl;cout << _month << endl;cout << _day << endl;
}

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

3.2 类模板的实例化

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

template<class T1, class T2>
class sroce
{
public:sroce(const T1& math, const T2& English);void Print();
private:T1 _math;T2 _English;
};template<class T1, class T2>
sroce<T1, T2>::sroce(const T1& math, const T2& English) :_math(math),_English(English)
{}template<class T1, class T2>
void sroce<T1, T2>::Print()
{cout << _math << '\n';cout << _English << '\n';
}int main()
{sroce<int, double> d1(10, 10.5);d1.Print();return 0;
}

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

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

相关文章

Leetcode990.等式方程的可满足性

题目 原题链接 等式方程的可满足性 思路 定义一个长度为26&#xff08;变量为小写字母&#xff09;的数组充当并查集&#xff0c;并将数组中的元素初始化为 -1判断“”并合并元素&#xff0c;将相等的放在一个集合中判断“!”&#xff1b;不等的如果在一个集合中&#xff0c;则…

2021世界人工智能大会召开 百度展示量子技术影响力

姓 名&#xff1a;王芷若 学 号&#xff1a;19020100180 学 院&#xff1a;电子工程学院 转载自&#xff1a;钥成网 原文链接&#xff1a; https://baijiahao.baidu.com/s?id1704906954970597725&wfrspider&forpc&searchword2021%E4%B8%9…

intellij idea 控制台运行java出现中文乱码的解决方法

原因&#xff1a; 字符编码不一致&#xff1a; 当你在intellij idea使用了UTF-8编码&#xff0c;而在控制台使用了其他编码&#xff08;比如gbk&#xff09;&#xff0c;就可能导致乱码。 文件读写编码问题&#xff1a; 如果读取文件时使用的编码与文件实际编码不一致&#xf…

AtCoder Regular Contest 156 C. Tree and LCS(思维题 构造 数学归纳法)

题目 构造一个排列p&#xff0c; 使得对于任意树上路径&#xff0c; 求该路径上的点(x1,...,xk)和对应排列上的点(Px1,...,Pxk)的最长公共子序列都得到一个值&#xff0c; 称为相似值 现在想令任意树上路径的相似值的最大可能长度最小&#xff0c; 最小化前提下&#xff0…

Redis笔记(基本操作+Java实现)

Redis是什么 一种数据库&#xff0c;但是不是mysql那样的表格&#xff0c;而是key-value的形式存储&#xff0c;而且它存在内存里&#xff0c;所以读写速度更快。 Redis常用数据类型 Redis常用命令简单使用 字符串操作 set name x get name 哈希操作 列表操作 集合操作 有…

自己开发了一个电脑上滚动背单词的软件

在这个快节奏的时代&#xff0c;我们每天都在忙碌中度过&#xff0c;手机虽然方便&#xff0c;但往往难以找到一整块时间来专心背单词。然而&#xff0c;你是否意识到&#xff0c;每天坐在电脑前的时间远比使用手机的时间要长&#xff1f;现在我们来介绍一个新型的学习软件灵思…

windows 驱动实例分析系列-COM驱动案例讲解

COM也被称之为串口,这是一种非常简单的通讯接口,这种结构简单的接口被广泛的应用在开发中,几乎所有系统都能支持这种通讯接口,它有RS232和RS485等分支,但一般我们都会使用RS232作为常见的串口,因为它足够简单和高效。 几乎所有的开发板,都会提供用于烧录、调试、日志的…

汽车总线之----FlexRay总线

Introduction 随着汽车智能化发展&#xff0c;车辆开发的ECU数量不断增加&#xff0c;人们对汽车系统的各个性能方面提出了更高的需求&#xff0c;比如更多的数据交互&#xff0c;更高的传输带宽等。现如今人们广泛接受电子功能来提高驾驶安全性&#xff0c;像ABS防抱死系统&a…

Nginx-HTTP和反向代理web服务器

概述 Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器 &#xff0c;同时也提供了IMAP/POP3/SMTP服务。Nginx是由伊戈尔赛索耶夫为俄罗斯访问量第二的Rambler.ru站点&#xff08;俄文&#xff1a;Рамблер&#xff09;开发的&#xff0c;公开版本1.19.6发布于20…

汽车总线之---- CAN FD总线

CAN FD 最高可支持8M/s的通信速率&#xff0c;从传统CAN到CAN FD的转换是很容易实施和推广的。 CAN FD报文的帧&#xff1a;标准帧&#xff0c;扩展帧 CAN FD 标准帧结构 CAN FD 报文的标准帧与CAN 报文的标准帧的区别 CAN FD 报文的标准帧与CAN FD报文的扩展帧的区别&…

手机在网状态查询接口如何用Java进行调用?

一、什么是手机在网状态查询接口&#xff1f; 手机在网状态查询接口&#xff0c;又叫运营商在网状态查询&#xff0c;手机号在网状态查询&#xff0c;传入手机号码&#xff0c;查询该手机号的在网状态&#xff0c;返回内容有正常使用、停机、在网但不可用、不在网&#xff08;…

JS 历史简介

目录 1. JS 历史简介 2. JS 技术特征 1. JS 历史简介 举例&#xff1a;在提交用户的注册信息的时候&#xff0c;为避免注册出现错误后重新填写信息&#xff0c;可以在写完一栏信息后进行校验&#xff0c;并提示是否出现错误&#xff0c;这样会大大提高用户提交的成功率&…

学习记录:js算法(四十二): 寻找两个正序数组的中位数

文章目录 寻找两个正序数组的中位数我的思路网上思路 总结 寻找两个正序数组的中位数 给定两个大小分别为 m 和 n 的正序&#xff08;从小到大&#xff09;数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], n…

美食共享圈:Spring Boot校园周边美食平台

第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面&#xff0c;分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…

解决 TortoiseGitPlink Fatal Error:深入解析

解决 TortoiseGitPlink Fatal Error&#xff1a;深入解析 在 Windows 平台上&#xff0c;开发者使用 Git 和 TortoiseGit 进行版本控制时&#xff0c;有时会遇到 TortoiseGitPlink Fatal Error。该错误通常是在推送/拉取代码时&#xff0c;客户端未能提供正确的 SSH 密钥。 1…

Unreal Engine 5 C++: Asset Batch Duplication插件编写02

目录 准备工作 "Scripting library" 三个最重要的功能&#xff08;前两个是UEditorUtilityLibrary中的&#xff09; 自动创建声明&#xff1a; TArray T 的含义 F 的含义 Live Coding &#xff08;Ctrlalt F11&#xff09; Live Coding 的工作流程&#xff…

SpringCloud-07 GateWay01 网关技术

Spring Cloud Gateway组件的核心是一系列的过滤器&#xff0c;通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防火墙和代理器&#xff0c;隐藏微服务结点IP端口信息&#xff0c;从而加强安全保护。Spring Clou…

PHP、Java等其他语言转Go时选择GoFly快速快速开发框架指南

概要 经过一年多的发展GoFly快速开发框架已被一千多家科技企业或开发者用于项目开发&#xff0c;它的简单易学得到其他语言转Go首选框架。且企业版的发展为GoFly社区提供资金&#xff0c;这使得GoFly快速框架得到良好的发展&#xff0c;GoFly技术团队加大投入反哺科技企业和开…

科研绘图系列:R语言ggplot2画热图(heatmap)

文章目录 介绍加载R包导入数据数据预处理画图导出数据系统信息介绍 热图(Heatmap)是一种数据可视化技术,它通过颜色的变化来表示数据的大小或者密度。热图通常用于展示两个变量之间的关系,或者在二维空间上展示数据的分布情况。以下是热图可以表示的一些内容: 数据分布:…

「C++系列」动态内存

【人工智能教程】&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站&#xff1a;【人工智能教程】 文章目录 一、动态内存1. 使用new和delete①分配单个对象②分配对象数组 2. …