<C++> 模板-上

news2024/12/23 16:52:47

 


目录

前言

一、函数模板

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.coloradmin.cn/o/1061034.html

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

相关文章

C++_pen_友元

友元&#xff08;破坏封装&#xff09; 我故意让别人能使用我的私有成员 友元类 friend class B;友元函数 friend void func();友元成员函数 friend void A::func();例 #include <stdio.h>class A;class C{ public:void CprintA(A &c); };class B{ public:void Bpri…

jira 浏览器插件在问题列表页快速编辑问题标题

jira-issueTable-quicker 这是一个可以帮助我们在问题表格页快速编辑问题的浏览器插件 github 地址 功能介绍 jira 不可否认是一个可以帮助有效提高工作效率的工具&#xff0c;但是我们在使用 jira 时使用问题表格可以让我们看到跟多的内容而不用关注细节&#xff0c;但是目…

c与c++中的字符串

在c中&#xff0c;string本质上是一个类&#xff1b; string与char *有些区别&#xff1a; char*是一个指针&#xff1b;string是一个类&#xff0c;类内封装了char*&#xff0c;管理这一个字符串&#xff0c;是一个char*的容器 在使用string类型时&#xff0c;要加上其头文…

用向量数据库Milvus Cloud 搭建AI聊天机器人

加入大语言模型(LLM) 接着,需要在聊天机器人中加入 LLM。这样,用户就可以和聊天机器人开展对话了。本示例中,我们将使用 OpenAI ChatGPT 背后的模型服务:GPT-3.5。 聊天记录 为了使 LLM 回答更准确,我们需要存储用户和机器人的聊天记录,并在查询时调用这些记录,可以用…

新版校园跑腿独立版小程序源码 多校版本,多模块,适合跑腿,外卖,表白,二手,快递等校园服务

最新校园跑腿小程序源码 多校版本&#xff0c;多模块&#xff0c;适合跑腿&#xff0c;外卖&#xff0c;表白&#xff0c;二手&#xff0c;快递等校园服务 此版本为独立版本&#xff0c;不需要** 直接放入就可以 需要自己准备好后台的服务器&#xff0c;已认证的小程序&#xf…

mysql面试题17:MySQL引擎InnoDB与MyISAM的区别

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL引擎InnoDB与MyISAM的区别 InnoDB和MyISAM是MySQL中两种常见的存储引擎,它们在功能和性能方面有一些区别。下面将详细介绍它们之间的差异。…

【微信小程序开发】一文学会使用CSS控制样式布局与美化

引言 在微信小程序开发中&#xff0c;CSS样式布局和美化是非常重要的一部分&#xff0c;它能够为小程序增添美感&#xff0c;提升用户体验。本文将介绍如何学习使用CSS进行样式布局和美化&#xff0c;同时给出代码示例&#xff0c;帮助开发者更好地掌握这一技巧。 一、CSS样式布…

基于HSV空间的彩色图像分割技术

1. 引言 每当我们看到图像时&#xff0c;它通常都是由各种元素和目标组成的。在某些情况下&#xff0c;我们可能会想要从图像中提取某个特定的对象&#xff0c;大家会怎么做&#xff1f;首先我们会想到的是进行crop相关的操作&#xff0c;这在某种程度上是可行的&#xff0c;但…

《数字图像处理-OpenCV/Python》连载(10)图像属性与数据类型

《数字图像处理-OpenCV/Python》连载&#xff08;10&#xff09;图像属性与数据类型 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第2章 图像的数据格式 在P…

AcCode项目测试报告

文章目录 项目介绍编写测试用例根据测试用例编写自动化测试0.搭建测试环境1. 创建功能类2. 编写注册功能自动化3.编写登录功能自动化 性能测试1.使用VUG编写性能测试脚本2. 创建测试场景3.开始执行4. 简单分析性能测试报告事务报告运行的虚拟用户图表点击率表吞吐量图表系统资源…

C#,数值计算——Sobol拟随机序列的计算方法与源程序

1 文本格式 using System; using System.Collections.Generic; namespace Legalsoft.Truffer { /// <summary> /// Sobol quasi-random sequence /// </summary> public class Sobol { public Sobol() { } public static void sobseq(int n,…

堆排序——向下调整

之前我们要想实现堆排序&#xff0c;是运用建堆代码来实现的&#xff1a; 向上调整建堆——向下调整排序 那么去我们可不可以只适用一种调整方法&#xff08;向下调整&#xff09;就能实现这样的功能呢&#xff1f; 向要只使用向下调整就实现堆排序 首先就是把数组里的值使用…

互联网Java工程师面试题·Dubbo 篇·第二弹

目录 18、Dubbo 用到哪些设计模式&#xff1f; 19、Dubbo 配置文件是如何加载到 Spring 中的&#xff1f; 20、Dubbo SPI 和 Java SPI 区别&#xff1f; 21、Dubbo 支持分布式事务吗&#xff1f; 22、Dubbo 可以对结果进行缓存吗&#xff1f; 23、服务上线怎么兼容旧版本&…

设计模式12、代理模式 Proxy

解释说明&#xff1a;代理模式&#xff08;Proxy Pattern&#xff09;为其他对象提供了一种代理&#xff0c;以控制对这个对象的访问。在某些情况下&#xff0c;一个对象不适合或者不能直接引用另一个对象&#xff0c;而代理对象可以在客户端和目标对象之间起到中介的作用。 抽…

星宿UI2.4资源付费变现小程序源码 支持流量主

第一个小程序为星宿小程序 目前是最新版2.0 搭建星宿需要&#xff1a;备用域名 服务器 微信小程序账号 功能&#xff1a;文章展示 文章分类 资源链接下载 轮播图 直接下载附件功能 很多 很适合做资源类分享 源码下载&#xff1a;https://download.csdn.net/download/m0_6604…

Android LitePal byte[]类型字段不被创建

我创建了以下实体类&#xff0c;主要是用户分享的内容、分享的照片、分享的标题&#xff0c;然后百度了一下LitePal可以识别byte[]&#xff0c;因为需要文件的上传与读取&#xff1a; public class Context extends LitePalSupport {private Integer ContextId;private String…

二叉树题目:路径总和 II

文章目录 题目标题和出处难度题目描述要求示例数据范围 前言解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;路径总和 II 出处&#xff1a;113. 路径总和 II 难度 4 级 题目描述 要求 给你二叉树的根结点 root \tex…

软件设计模式系列之二十五——访问者模式

访问者模式&#xff08;Visitor Pattern&#xff09;是一种强大的行为型设计模式&#xff0c;它允许你在不改变被访问对象的类的前提下&#xff0c;定义新的操作和行为。本文将详细介绍访问者模式&#xff0c;包括其定义、举例说明、结构、实现步骤、Java代码实现、典型应用场景…

【2023年11月第四版教材】第18章《项目绩效域》(第一部分)

第18章《项目绩效域》&#xff08;第一部分&#xff09; 1 章节内容2 干系人绩效域2.1 绩效要点2.2 执行效果检查2.3 与其他绩效域的相互作用 3 团队绩效域3.1 绩效要点3.2 与其他绩效域的相互作用3.3 执行效果检查3.4 开发方法和生命周期绩效域 4 绩效要点4.1 与其他绩效域的相…

电脑重置 Win 10系统

文章目录 电脑重置系统操作步骤一、右键 开始→ 设置二、点击 更新与安全三、点击 恢复四、点击 开始四、按需二选一五、以本地重新安装为例&#xff0c;点击 下一页六、点击 重置七、重新进行Windows设置 当电脑出现系统文件损坏、磁盘掉盘等情况&#xff0c;可以考虑重装系统…