<C++> 模板-上

 


目录

前言

一、函数模板

1. 概念

 2. 格式

3. 原理

4. 函数模板的实例化

4.1 隐式实例化

4.2 显示实例化

5. 模板参数的匹配原则    

5.1 

5.2 

5.3 

二、类模板

1. 类模板定义格式

2. 类模板的实例化

总结


前言

        如何实现一个通用的函数,函数可以实现两个类型的交换?

        在往常,我们可能会写下可能用到的类型交换的函数,进行函数重载,但是类型是无穷的,整形、字符型、浮点型、自定义类型...,我们是不可能重载完所有的交换函数,并且函数重载也是有缺点的

例如:

        1. 代码复用性比较低,只要有新的类型出现,就需要再次进行函数重载

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

        C++中,增加了模板这一关键字可以使编译器根据不同的类型,利用模板来生成相应的代码。

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


一、函数模板

1. 概念

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

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

        比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

 2. 格式

template <typename T1, typename T2, ......, typename Tn>
返回值类型  函数名  (形参列表)
{}

 例如:

template<typename T>  // 模板参数 -- 类型
void Swap(T& x1, T& x2)
{T tmp = x1;x1 = x2;x2 = tmp;
}

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

//参数为多个模板,返回值也是模板
template<typename T1, typename T2>
T1 Func(const T1& x, const T2& y)
{cout << x << " " << y << endl;return x;
}

3. 原理

        函数模板是一个蓝图,它本身并不是函数(类似于类和对象的关系),是编译器用使用方式产生特定具体类型函数的模具。所以模板就是将本来应该我们做的重复的事情交给了编译器。

        所以,我们在调用模板函数时,真正调用的不是模板,而是模板根据实参的类型实例化的函数 

4. 函数模板的实例化

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

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

4.1 隐式实例化

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

当只有一个模板时,实参有两种类型,这时编译器就不知道应该推演T为哪种类型,这就需要我们手动强制类型转换

template<class T>
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;// 实参传递的类型,推演T的类型cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;cout << Add(a1, (int)d1) << endl;cout << Add((double)a1, d1) << endl;// 显示实例化,用指定类型实例化cout << Add<int>(a1, d1) << endl;cout << Add<double>(a1, d1) << endl;return 0;
}

        注意:对于模板Add函数而言,形参被const修饰,一旦去掉,我们写的代码就跑到不动了,因为我们在调用该模板时,使用了强制类型转换,转换时会产生临时变量,而临时变量具有常性,因为应用的权限不能放大,所以形参必须要用const修饰 

4.2 显示实例化

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

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

        指定为int后,double型变量b就隐式类型转换为int 

        如果手动的显示实例化类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

        但是上面所述的情况显式实例化的真正用途,因为用两个模板就可以解决上面的问题。

        真正会用到显式实例化的情况:有些函数无法自动推导,那么就只能显式实例化.

例:

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

        当调用该模板时,改模板推导不出返回值类型,所以这里就真正的用到显式实例化的功能

int main()
{double* p1 = Alloc<double>(10);
}

      

5. 模板参数的匹配原则    

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

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

二、类模板

        由于数据结构中,我们学习过顺序表、栈、队列等等数据结构,但是他们都只能使用一种数据类型,当要使用另一种数据类型时,就需要再拷贝一份并修改里面的数据类型,如果这样使用,那么每使用一个数据类型,我们都需要拷贝一份并修改里面的数据类型,并且,如果原数据结构出现错误,我们需要修改所有的代码。类模板解决了这个问题。

1. 类模板定义格式

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

例:

// 动态顺序表
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{ 
public :Vector(size_t capacity = 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}// 使用析构函数演示:在类中声明,在类外定义。~Vector();void PushBack(const T& data);void PopBack();// ...size_t Size() {return _size;}T& operator[](size_t pos){assert(pos < _size);return _pData[pos];}private:T* _pData;size_t _size;size_t _capacity;
};

 注意:在模板类中,若要声明与定义分离,那么在类外的定义处,不能只写类名,需要加上模板,并在类名后加上<T>

// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{if(_pData)delete[] _pData;_size = _capacity = 0;
}

2. 类模板的实例化

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

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


总结

最后,如果小帅的本文哪里有错误,还请大家指出,请在评论区留言(ps:抱大佬的腿),新手创作,实属不易,如果满意,还请给个免费的赞,三连也不是不可以(流口水幻想)嘿!那我们下期再见喽,拜拜!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux 本地 Docker Registry本地镜像仓库远程连接

Linux 本地 Docker Registry本地镜像仓库远程连接 Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现远程pull or push (拉取和推送)镜像,不受本地局域网限制&#xff01; 1. 部署Docker Registry 使用官网安装方式,docker命令一键启动,该命令启动一个regis…

MySQL语句大总结

基础语法数据库约束复杂语法1&#xff1a;聚合查询&#xff08;所谓聚合计算聚合函数的结果&#xff09;2&#xff1a;联合查询什么是内连接&#xff1b;什么是外连接&#xff1f;3&#xff1a;子查询&#xff08;套娃,慎用&#xff09;4&#xff1a;合并查询 基础语法 建库 c…

【面试总结大纲】

面试 1. springSpring AOP的具体实现核心概念分别指的是什么?基于注解的切面实现主要包括以下几个步骤&#xff1a;两个切面&#xff0c;它们之间的顺序是怎么控制的 springmvc的工作流程设计模式原则Spring 框架中用到了哪些设计模式&#xff1f; 2. Java-锁2.1锁的分类可重入…

PostgreSQL ash —— pgsentinel插件

一、 插件作用 众所周知&#xff0c;pg是没有像oracle那样的ash视图的&#xff0c;因此要回溯历史问题不太方便。pgsentinel插件会将pg_stat_activity与pg_stat_statements视图内容定期快照&#xff0c;并存入pg_active_session_history和pg_stat_statements_history视图中。 1…

一文搞懂APT攻击

APT攻击 1. 基本概念2. APT的攻击阶段3. APT的典型案例参考 1. 基本概念 高级持续性威胁&#xff08;APT&#xff0c;Advanced Persistent Threat&#xff09;&#xff0c;又叫高级长期威胁&#xff0c;是一种复杂的、持续的网络攻击&#xff0c;包含高级、长期、威胁三个要素…

【JavaEE】JavaScript

JavaScript 文章目录 JavaScript组成书写方式行内式内嵌式外部式&#xff08;推荐写法&#xff09; 输入输出变量创建动态类型基本数据类型数字类型特殊数字值 String转义字符求长度字符串拼接布尔类型undefined未定义数据类型null 运算符条件语句if语句三元表达式switch 循环语…

问题: 视频颜色问题,偏绿

参考 什么是杜比视界&#xff1f; - https://www.youtube.com/watch?vldXDQ6VlC7g 【哈士亓说】07&#xff1a;HDR、杜比视界究竟是个啥&#xff1f;为什么这个视频还不是HDR视频&#xff1f; - https://www.youtube.com/watch?vrgb9Xg3cJns 正文 视频应该是 杜比视界 电…

windows系统服务管理命令sc

sc可以用于管理系统服务、计划任务、系统日志等方面&#xff0c;是不可或缺的神器。 基本用法 在命令提示符下输入sc命令&#xff0c;然后按回车键。 上图展示的是sc命令的使用方法&#xff0c;支持哪些参数实现哪些功能 要查看系统所有服务列表&#xff0c;包括它们是否正在…

区别对比表:阿里云轻量服务器和云服务器ECS对照表

阿里云轻量应用服务器和云服务器ECS区别对照表&#xff0c;一看就懂的适用人群、使用场景、优缺点、使用限制、计费方式、网路和镜像系统全方位对比&#xff0c;阿里云服务器网分享ECS和轻量应用服务器区别对照表&#xff1a; 目录 轻量应用服务器和云服务器ECS区别对照表 轻…

Spring Security 6.1.x 系列 (1)—— 初识Spring Security

一、 Spring Security 概述 Spring Security是Spring组织提供的一个开源安全框架&#xff0c;基于Spring开发&#xff0c;所以非常适合在Spring Boot中使用。 官方文档地址&#xff1a;https://docs.spring.io/spring-security/reference/index.html GitHub地址&#xff1a;…

2023年CSP-J真题详解+分析数据(选择题篇)

目录 前言 2023CSP-J江苏卷详解 小结 前言 下面由我来给大家讲解一下CSP-J的选择题部分。 2023CSP-J江苏卷详解 1.答案 A 解析&#xff1a;const在C中是常量的意思&#xff0c;其作用是声明一个变量&#xff0c;值从头至尾不能被修改 2.答案 D 解析&#xff1a;八进制…

大压缩作用下软基底薄膜周期性分层现象的研究

引言 通过实验、理论模型和有限元模拟的结合&#xff0c;英思特通过将一个薄膜粘接到一个预应变超过400%的软弹性衬底上&#xff0c;探索了微观和宏观尺度上控制周期性屈曲脱层形成和发展的机理。我们发现&#xff0c;在大的基底预应变释放时&#xff0c;膜中的变形遵循三阶段…