C++模板

news2024/12/21 16:30:55

fcf6292a67ec49bfb426abf42aa06b77.jpeg

目录

​一、认识模板

1.什么是模板

2.模板的分类

二、函数模板

1.泛型和函数模板

2.函数模板的格式

三、类模板

四、实例化

1.隐式实例化

2.显式实例化

3.隐式类型转换

4.模板参数的匹配原则


一、认识模板

1.什么是模板

模板(Template)指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。C++ 的标准库提供许多有用的函数大多结合了模板的观念,如STL以及IO Stream。模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

2.模板的分类

模板分为函数模板和类模板,函数模板针对参数类型不同的函数;类模板针对数据成员和成员函数类型不同的类。

模板支持与了类型无关的代码的编写。

二、函数模板

1.泛型和函数模板

编写与类型无关的通用代码,是代码复用的一种手段。

比如说,我们定义一个交换intl类型元素值的函数。

void swap(int& a, int& b)
{
    int temp = 0;
    temp = a;
    a = b;
    b = temp;
}

这个函数可以交换int类型的变量值,但是只能操作int类型。如果我们需要交换double类型的变量,按照C++的逻辑就需要再次定义一个新的重载函数。

void swap(double& a, double& b)
{
    double temp = 0;
    temp = a;
    a = b;
    b = temp;
}

实现所有类型变量的交换需要写太多逻辑相同的函数,过于冗余。那么,如果我们不指定这个参数的类型,用一个泛型去替代这些类型,让编译器去推导这个参数的具体类型,那么我们就只需要一个函数定义了。

这样的泛型函数就叫做模板,内部变量的类型叫做泛型。

2.函数模板的格式

template<typename T1, typename T2,......,typename Tn>//typename也可以换成class
返回值类型 函数名 ( 参数列表 )
{}
template<typename T1>//用template关键字定义泛型
void swap(T1& a, T1& b)//内部变量也用泛型
{
    T1 temp = 0;
    temp = a;
    a = b;
    b = temp;
}

可以定义多个泛型T1、T2、T3等等,一个泛型只能推导出一个具体类型。T1可以推导为int类型,但是不能又推导为int,又推导为其他类型。

三、类模板

我们定义一个没有完全写好的栈

#define TYPE int
class Stack
{
public:
    Stack()
        :_a((TYPE*)malloc(sizeof(TYPE)* 4))
        ,_size(0)
        , _volume(0)
    {}
    void push(TYPE data)
    {
        _a[_size++] = data;
    }
private:
    TYPE* _a;
    int _size;
    int _volume;
};

虽然通过改变TYPE对应的类型可以改变存储数据的类型,但是如果我们想同时使用一个储存int类型元素的栈和一个储存double类型元素的栈,那么还需要定义另一个栈的类,依旧冗余。所以类似于函数,类也可以使用泛型。这种使用泛型的类也叫做类模板,与函数模板相似。

template<typename T1>
class Stack
{
public:
    Stack()
        :_a((T1*)malloc(sizeof(T1)* 4))
        ,_size(0)
        , _volume(0)
    {}
    void push(T1 data)
    {
        _a[_size++] = data;
    }
private:
    T1* _a;
    int _size;
    int _volume;
};

四、实例化

1.隐式实例化

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数和类的声明,相当于建筑的图纸,只有使用到这个函数和类时才会定义。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

简单说就是本来我们应该多去写的Swap函数和Stack类的重复工作去给编译器做了。

这是我们之前的函数模板

template<typename T1>//用template关键字定义泛型
void swap(T1& a, T1& b)//内部变量也用泛型
{
    T1 temp = 0;
    temp = a;
    a = b;
    b = temp;
}

对于不同类型的变量进行swap,当编译器遇到符合模板但没有定义的函数,编译器就会自己生成一个对应的重载函数,如果这个函数之前定义过那就使用之前定义过的函数。

template<typename T1>
void swap(T1& a, T1& b)
{
    T1 temp = 0;
    temp = a;
    a = b;
    b = temp;
}
int main()
{
    int a = 1;
    int b = 2;
    swap(a,b);
    //交换两个int变量a和b,编译器会根据模板定义一个int类型的交换函数,如下:
    //void swap(int& a, int& b)
    double c = 1.0;
    double d = 2.0;
    swap(c,d);
    //交换两个double变量c和d,编译器会根据模板再次定义一个double类型的交换函数,如下:
    //void swap(double& a, double& b)
    int e = 1;
    int f = 2;
    swap(e,f);
    //再次交换两个int变量e和f,编译器会继续使用之前定义的int类型交换函数
    //void swap(int& a, int& b)
    return 0;
}

最后的结果还是定义了很多不同类型的重载函数,与我们自己定义许多不同类型的函数的结果是一样的。但是这时不再需要程序员去一个一个类型定义函数,大大简化了程序的代码量。

模板对于类也是一样的效果,也会自己定义许多不同类型的类去使用,但是类只支持显式实例化。

2.显式实例化

我们不光可以让计算机自己推断类型,而且也可以自己指定生成哪一种类型参数的函数和类。

template<typename T1>//定义泛型T1,在这里也表示下面的函数中会用到T1
void Swap(T1& a, T1& b)
{
    T1 temp = 0;
    temp = a;
    a = b;
    b = temp;
}
template<typename T1, typename T2>//定义泛型T2,T1在前面已经定义了表示会用到T1和T2
void print(T1& a, T2& b)//注意,这个T1经过推导只能对应一个类型,不能在上面的函数中是int下面的是double
{
    cout << a << ' ' << b << endl;
}
int main()
{
    int a = 1;
    int b = 2;
    double c = 1.0;
    Swap<int>(a, b);//在函数后面加<类型>就可以指定定义和使用对应类型的函数
    print<int, double>(a, c);//<>内部多个类型用,隔开对应上面的template
    cout << a << ' ' << b << endl;
    return 0;
}
//输出:
//2 1
//2 1

之前说过,类只支持显式实例化,不能通过编译器推断。类模板也是一个声明或者说是一个蓝图,只有使用了这个类型的函数或者类才会被定义。

template<typename T>
class Stack
{
public:
    Stack()
        :_a((T*)malloc(sizeof(T)* 4))
        , _size(0)
        , _volume(0)
    {}
    void push(T data)
    {
        _a[_size++] = data;
    }
private:
    T* _a;
    int _size;
    int _volume;
};

int main()
{
    Stack<int> s1;//定义一个储存int类型的类,类型为Stack<int>
    Stack<double> s2;//定义一个储存double类型的类,类型为Stack<double>
    s1.push(1);//int类型栈可以插入数据
    s2.push(1.0);//double类型栈也可以插入数据
    return 0;
}

3.隐式类型转换

我们可以清楚地看到T会推导出两个变量类型int和double,此时T还是会推导为int,但是b参数会隐式转化为int,我们知道这个转换的临时参数是有常性的,所以需要用const修饰。

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

int main()
{
    int a = 10;
    double b = 20.2;
    cout << Add<int>(a, b) << endl;//调用int类型Add函数,b生成一个临时int常量传递给函数
    return 0;
}

在不能完成隐式类型转换时,程序就会报错。

4.模板参数的匹配原则

  • 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模 板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
  • 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

 

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

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

相关文章

Java笔记(十一)

文献种类&#xff1a;专题技术总结文献 开发工具与关键技术&#xff1a; IntelliJ IDEA、Java 语言 作者&#xff1a; 方建恒 年级&#xff1a; 2020 撰写时间&#xff1a; 2022 年 10 月 28 日 Java笔记(十一) 今天我给大家继续分享一下我的Java笔记&#xff0c; 我们来了解…

CTFHub | 报错注入

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

第二站:分支与循环(第二幕)

目录 三、循环 1.while循环 &#xff08;1&#xff09;基本原理与用法 &#xff08;2&#xff09;break在while循环中的作用 &#xff08;3&#xff09;continue在while循环中的作用 &#xff08;4&#xff09;一图总结while循环 2.for循环 &#xff08;1&#xff09;基…

[SpringBoot] 多模块统一返回格式带分页信息

✨✨个人主页:沫洺的主页 &#x1f4da;&#x1f4da;系列专栏: &#x1f4d6; JavaWeb专栏&#x1f4d6; JavaSE专栏 &#x1f4d6; Java基础专栏&#x1f4d6;vue3专栏 &#x1f4d6;MyBatis专栏&#x1f4d6;Spring专栏&#x1f4d6;SpringMVC专栏&#x1f4d6;SpringBoot专…

算法刷题路线总结与相关资料分享

算法刷题路线总结与相关资料分享前言一、算法刷题路线总结二、算法题刷题步骤三、基础数据结构与算法知识1、时间复杂度2、空间复杂度3、线性表4、栈与队列5、树四、算法学习相关资料推荐1.数据结构与算法基础2.专项刷题路线资料3.算法课程视频资料后记前言 本文为算法刷题路线…

双十一数码产品哪些值得买?双十一好物产品分享

双十一必然是数码产品最值得买的&#xff0c;因为这类产品的优惠力度往往是最大的&#xff0c;所以每年的双十一都是升级数码设备的好时机&#xff0c;今天为大家带来的是便是个人推荐的双十一数码好物。好了&#xff0c;废话不再多说&#xff0c;我们开车吧。 一、不伤耳的骨…

postman 实用教程(含带 token 访问需登录权限的接口)

下载安装 Postman 访问官网下载安装 Postman https://www.postman.com/downloads/?utm_sourcepostman-home 新建文档 右键菜单可以重命名 新建接口 选择接口类型输入接口若传入参数格式为 json &#xff0c;则选择 Body 中的 raw 和 JSON输入传入的参数&#xff08;json格式&a…

计算机网络--数据链路层

今天来讲网络协议栈的最后一层&#xff0c;数据链路层(物理层我们不考虑了)&#xff0c;我们之前学到&#xff0c;TCP协议提供了数据传输的可靠性&#xff0c;IP层决定数据报从哪到哪&#xff0c;那么数据报是如何从一个结点到下一个结点呢&#xff1f;得到相应如何返回呢&…

(02)Cartographer源码无死角解析-(09) gflags与glog简介、及其main函数讲解

本人讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文…

软件工程结构化设计

目录 结构化分析与结构化设计的关系&#xff1a; 体系结构设计概念&#xff1a; 图形工具&#xff1a; 层次图&#xff1a;调用关系​编辑 HIPO图&#xff1a;层次图IPO图 软件结构图&#xff1a; 软件设计原则&#xff1a; 模块化&#xff1a; 模块划分注意事项&#xf…

巴什博弈——范围拿物品问题

巴什博弈 巴什博弈&#xff08;Bash game&#xff09; 是一个双人博弈&#xff1a;有一堆总数为n的物品&#xff0c;2名玩家轮流从中拿取物品。每次至少拿1件&#xff0c;至多拿m件&#xff0c;不能不拿&#xff0c;最终将物品拿完者获胜。 巴什博弈除了两人轮流按一定数量拿物…

【黄啊码】MySQL入门—14、细说数据库的MVCC机制

大家好&#xff0c;我是黄啊码。上一篇文章中&#xff0c;我们讲到了锁的划分&#xff0c;以及乐观锁和悲观锁的思想。今天我们就来看下 MVCC&#xff0c;它就是采用乐观锁思想的一种方式。那么它到底有什么用呢&#xff1f; 我们知道事务有 4 个隔离级别&#xff0c;以及可能…

共谋韬略、共巢未来,电巢与韬略“战略合作签约仪式”圆满举办!

前言 2022年10月27日下午&#xff0c;电巢科技与韬略科技齐聚深圳南山&#xff0c;共同举办了隆重的战略合作签约仪式&#xff0c;双方就整合核心资源、共同打造高质量数字化内容等战略方针达成了一致&#xff0c;携手开启合作新篇章。 电巢科技和韬略科技基于相契合的发展战略…

Numpy基础教程

1 Numpy 对象2 Numpy创建numpy.array 构造器来创建numpy.emptynumpy.zerosnumpy.onesnumpy.arangeNumpy索引3 Numpy常用操作numpy.reshapenumpy.reshape(arr,newshape,order C)numpy.transposenumpy.expand_dimsnumpy.squeezeNumpy功能十分强大的python扩展库&#xff0c;数学…

基于Java+Springboot+Vue+elememt美食论坛平台设计实现

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

07-树(Tree)结构分析

文章目录树(Tree)结构分析什么是树&#xff1f;树中的相关名词如何理解&#xff1f;什么是二叉树&#xff1f;什么是二叉搜索树&#xff1f;什么是AVL树&#xff1f;什么是2-3树&#xff1f;什么是红黑树&#xff1f;总结&#xff08;Summary&#xff09;树(Tree)结构分析 什么…

【飞桨PaddleSpeech语音技术课程】— 语音识别-流式服务

FastAPI websocket 流式语音识别服务 0. 背景 流式语音识别(Streaming ASR)或者在线语音识别(Online ASR) 是随着输入语音的数据不断增加&#xff0c;实时给出语音识别的文本结果。与之相对的是非实时或者离线语音识别&#xff0c;是传入完整的音频数据&#xff0c;一次给出整…

ppocrlabel简单教学

前言 给我们小白成员的快速上手ppocrlabel的指南 1. ppocr环境配置 建议是先创建一个虚拟环境 【直接参考】&#xff1a;https://blog.csdn.net/weixin_42708301/article/details/119864744 2. ppocrlabel环境安装 【参考文档】PaddleOCR-release-2.6\PPOCRLabel\README_c…

将STM32 内部Flash虚拟成优盘,进行IAP升级

书接上回&#xff0c;上篇文章已经成功的将 STM32 内部FLASH虚拟成优盘进行文件存储了。 【将 STM32 内部Flash虚拟成优盘】https://blog.csdn.net/qq_44810226/article/details/127508789 然后我们开始固件升级流程&#xff1a; 从上图可以看出&#xff0c;固件存储的位置是不…

Python-代码封装思想

继上文所将讲的pythonrequestsUnittest框架&#xff0c;本文将继续分享python代码的进一步封装思想&#xff0c;来提高代码的整体运行效率及整洁性&#xff0c;本文以接口测试框架为例进行讲解。 关于Unittest单元测试框架的具体使用方法链接链接&#xff08;点击跳转&#xf…