C++中的类模版

news2024/11/13 10:23:30

🐶博主主页:@ᰔᩚ. 一怀明月ꦿ 

❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C++

🔥座右铭:“不要等到什么都没有了,才下定决心去做”

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀

目录

🐰类模版

🌸类模版的声明

🌸类模版的实例化

🌸类模版参数

🌸默认模版实参


🐰类模版

运用函数模版可以设计出与数据类型无关的通用函数。与之相似的,C++也支持用类模版来设计结构和成员函数,但是所处理数据类型不同的通用类。在设计模版类时,可以使其中的某些数据成员、成员函数的参数或返回值与具体类型无关。

模版在C++中更多的使用是在类的定义中,最常见的就是STL和ATL,它们都是作为C++标准集成在VC++开发环境中的标准模版库

🌸类模版的声明

类模版声明的格式:
template<typename T1,typename T2,...>
class 类名
{
  类体
};

与函数模版一样,template是声明类模版的关键字,"<>"中T1、T2是类模版的类型参数。在一个类型模版中,可以定义多个不同的类型参数。"<>"中的typename和class可以互换,但与“类名”前的class具有不同的函数含义,二者没有关系。“类名”前的class表示类的声明

例如:
下面的堆栈类模版Stack
#include<iostream>
using namespace std;
const int SSize=10;//SSize为栈的容量
template<typename T>
class Stack
{
public:
    Stack()
    {
        top=0;
    }
    void push(T e);//入栈
    T pop();//出栈
    bool stackEmpty()//判断栈是否为空
    {
        return top==0;
    }
    bool stackFull()//判断栈是否为满
    {
        return top==SSize;
    }
private:
    T data[SSize];
    int top;
};
template<typename T>
void Stack<T>::push(T e)
{
    if(stackFull())
    {
        cout<<"Stack is Full! Don't push data!"<<endl;
        return ;
    }
    data[top]=e;
    top++;
}
template<typename T>
T Stack<T>::pop()
{
    if(stackEmpty())
    {
        cout<<"Stack is Empty! Don't pop data!"<<endl;
        return ;
    }
    top--;
    return data[top];
}

注意:

(1)类模版中的成员函数即可以在类模版内定义,也可以在类模版外定义

如果在类模版内定义成员函数,其与普通成员函数的定义方式一样,例如Stack的构造函数、stackEmpty、stackFull的定义

如果在类模版外定义成员函数,采用以下形式:
template<模版参数列表>
返回值类型 类名<模版参数列表>::成员函数名(参数列表)
{
    函数体
}

例如:

Stack中的push成员函数

template<typename T>
void Stack<T>::push(T e)
{
    if(stackFull())
    {
        cout<<"Stack is Full! Don't push data!"<<endl;
        return ;
    }
    data[top]=e;
    top++;
}
一定注意:引用模版类名的地方,必须伴有该模版的参数列表
(2)如果在类模版外将成员函数定义为inline(内联)函数,应将inline关键字加在类模版的声明后。
例如:
template<typename T>
inline T Stack<T>::pop(){...}

(3)类模版的成员函数的定义必须同类模版的定义在同一个文件中因为,类模版定义不同与类的定义,编译器无法通过一般的手段找到类模版的成员函数的代码,只有将它和类模版定义放一起,才能保证类模版正常使用。一般都放在一个头文件中(.h文件中)

🌸类模版的实例化

在声明一个类模版后,如何去使用它?
例如:
Stack<int>int_stack;

用Stack类模版定义了一个对象int_stack。编译器遇到该语句,会使用int去替换Stack类模版中的所有类型模版参数T,生成一个针对int类型数据的具体类,一般称为模版类,

如下:

class Stack
{
public:
    Stack()
    {
        top=0;
    }
    void push(int e);//入栈
    int pop();//出栈
    bool stackEmpty()//判断栈是否为空
    {
        return top==0;
    }
    bool stackFull()//判断栈是否为满
    {
        return top==SSize;
    }
private:
    int data[SSize];
    int top;
};

 

由此可以看出,类模版、模版类以及模版对象之间的关系为:由类模版实例化生成针对具体数据类型的模版类,在由模版类定义模版对象。

用模版类定义对象形式:
类模版名<实际模版参数列表>对象名;
类模版名<实际模版参数列表>对象名(构造函数的参数列表);

由类模版创建实例模版类时,必须为类模版的每个模版参数显式指定模版实参。然而,由函数模版创建其实例模版函数时,可以不显式指定模版实参。

注意:
在类模版实例化的过程中,并不会实例化类模版的成员函数 ,也就是说,在用类模版定义对象时并不会生成类成员函数的代码。 只有成员函数被调用时才会被实例化,编译器才会生成其真正代码。

🌸类模版参数

与函数模版的模版参数一样,类模版参数中也可以出现非类型参数

对于前面堆栈类模版Stack,也可以不定义一个int型常变量SSize来指定栈容量大小,而改成为其增加一个非类型参数

#include<iostream>
using namespace std;
template<typename T,int SSize>
class Stack
{
public:
    Stack()
    {
        top=0;
    }
    void push(T e);//入栈
    T pop();//出栈
    bool stackEmpty()//判断栈是否为空
    {
        return top==0;
    }
    bool stackFull()//判断栈是否为满
    {
        return top==SSize;
    }
private:
    T data[SSize];
    int top;
};
template<typename T,int SSize>
void Stack<T,SSize>::push(T e)
{
    if(stackFull())
    {
        cout<<"Stack is Full! Don't push data!"<<endl;
        return ;
    }
    data[top]=e;
    top++;
}
template<typename T,int SSize>
T Stack<T,SSize>::pop()
{
    if(stackEmpty())
    {
        cout<<"Stack is Empty! Don't pop data!"<<endl;
        return ;
    }
    top--;
    return data[top];
}

当需要这个模版的一个实例时,模版类创建一个对象时,必须为非类型参数SSize显式提供一个编译时常数

例如:
Stack<int,10>int_stack;

🌸默认模版实参

在类模版中,可以为模版提供默认实参。 例如,为了使上述固定大小的Stack类模版,可以为其非类型模版参数SSize提供默认参数
例如:
template<typename T,int SSize=10>
class Stack
{
public:
    Stack()
    {
        top=0;
    }
    void push(T e);//入栈
    T pop();//出栈
    bool stackEmpty()//判断栈是否为空
    {
        return top==0;
    }
    bool stackFull()//判断栈是否为满
    {
        return top==SSize;
    }
private:
    T data[SSize];
    int top;
};

类模版参数的默认实际参数是一个类型或值当模版被实例化时,如果没有指定实际参数,则使用该类型或值注意,默认实际参数应该是一个“对类模版实例的多数情况都适合”的类型或值现在,如果创建一个Stack模版的对象时忽略了第二个模版参数,SSize的默认值就是10

注意:
(1)作为默认的模版实参,它们只能被定义一次,编译器会知道第一次的模版声明或定义

(2)指定默认实参的模版参数必须放在模版形参列表的右端,否则出错(和重载函数参数列表一样,带有默认值的参数必须放右端)

例如:

template<typename T1,typename T2,typename T3=int,int SSize=10>//正确
template<typename T1,typename T2=int,typename T3,int SSize=10>//错误

(3)可以为所有的模版参数提供实参但声明,如果用Stack类模版实例化一个对象时,如果全部都想使用模版参数的默认值,就必须使用一对尖括号,这样编译器就知道说明了一个类模版例如:

#include<iostream>
using namespace std;
template<typename T=int,int SSize=10>
class Stack
{
public:
    Stack()
    {
        top=0;
    }
    void push(T e);//入栈
    T pop();//出栈
    bool stackEmpty()//判断栈是否为空
    {
        return top==0;
    }
    bool stackFull()//判断栈是否为满
    {
        return top==SSize;
    }
private:
    T data[SSize];
    int top;
};
template<typename T,int SSize>//这里千万不要写成template<typename T=int,int SSize=10>,因为作为默认的模版实参,它们只能被定义一次
void Stack<T,SSize>::push(T e)
{
    if(stackFull())
    {
        cout<<"Stack is Full! Don't push data!"<<endl;
        return ;
    }
    data[top]=e;
    top++;
}
template<typename T,int SSize>//这里千万不要写成template<typename T=int,int SSize=10>,因为作为默认的模版实参,它们只能被定义一次
T Stack<T,SSize>::pop()
{
    if(stackEmpty())
    {
        cout<<"Stack is Empty! Don't pop data!"<<endl;
        return 1;
    }
    top--;
    return data[top];
}
int main()
{
    Stack<>int_stack;//注意空的尖括号,这里全部是用类模版参数的默认值
    int_stack.push(5);
    cout<<int_stack.pop()<<endl;
    return 0;
}
结果:
5

类模版的模版形参列表中的参数类型有三种:类型参数、非类型参数和类模版的参数,函数模版的模版参数类型也与此相同。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸   

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

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

相关文章

Linux驱动开发——高级I/O操作(一)

一个设备除了能通过读写操作来收发数据或返回、保存数据&#xff0c;还应该有很多其他的操作。比如一个串口设备还应该具备波特率获取和设置、帧格式获取和设置的操作;一个LED设备甚至不应该有读写操作&#xff0c;而应该具备点灯和灭灯的操作。硬件设备是如此众多&#xff0c;…

PDF怎么转CAD文件?(免费!高效转换方法汇总)

一般而言&#xff0c;PDF图纸是不能修改的。若需修改&#xff0c;则需将PDF转CAD&#xff0c;此时如何满足PDF转CAD的需求呢&#xff1f;今天&#xff0c;我将教你两种免费的PDF转CAD的方法&#xff0c;助力高效办公。 1.本地软件转换法 这是用本地软件转换方法&#xff0c;支…

【系统集成项目管理工程师】项目管理一般知识

&#x1f4a5;项目管理一般知识 一、什么是项目 1、项目定义 项目是为达到特定的目的&#xff0c;使用一定资源&#xff0c;在确定的期间内&#xff0c;为特定发起人提供独特的产品、服务或成果而进行的一系列相互关联的活动的集合。项目有完整的生命周期&#xff0c;有开始…

Dubbo(超级无敌认真好用,万字收藏篇!!!!)

文章目录Dubbo前言大型互联网架构目标集群和分布式集群分布式架构演进1 Dubbo概述1.1 Dubbo概念1.2 Dubbo架构图2 Dubbo快速入门2.1 Zookeeper的安装2.2 springBoot整合DubboZookeeper2.2.1 创建项目Dubbo--provider2.2.2 创建项目Dubbo--consumer2.2.3 测试3 Dubbo高级特性3.1…

可视化 | Flask+Pyecharts可视化模板

文章目录&#x1f3f3;️‍&#x1f308; 1. 系统说明界面&#x1f3f3;️‍&#x1f308; 2. 柱状图示例界面&#x1f3f3;️‍&#x1f308; 3. 饼状图示例界面&#x1f3f3;️‍&#x1f308; 4. 折现图示例界面&#x1f3f3;️‍&#x1f308; 5. 散点图示例界面&#x1f3…

人工智能(Pytorch)搭建transformer模型,真正跑通transformer模型,深刻了解transformer的架构

大家好&#xff0c;我是微学AI&#xff0c;今天给大家讲述一下人工智能(Pytorch)搭建transformer模型&#xff0c;手动搭建transformer模型&#xff0c;我们知道transformer模型是相对复杂的模型&#xff0c;它是一种利用自注意力机制进行序列建模的深度学习模型。相较于 RNN 和…

【数据结构Java】--图、BFS、DFS、拓扑结构

目录 一、图&#xff08;Graph&#xff09; 1.概念 2.有向图 3.出度、入度 4.无向图 5.简单图、多重图 6.无向完全图 7.有向完全图 8.有权图 9.连通图 10.连通分量&#xff08;无向图&#xff09; 11.强连通图&#xff08;有向图&#xff09; 12.强连通分量 13.邻接矩…

微服务架构-服务网关(Gateway)-权限认证(分布式session替代方案)

权限认证-分布式session替代方案 前面我们了解了Gateway组件的过滤器&#xff0c;这一节我们就探讨一下Gateway在分布式环境中的一个具体用例-用户鉴权。 1、传统单应用的用户鉴权 从我们开始学JavaEE的时候&#xff0c;就被洗脑式灌输了一种权限验证的标准做法&#xff0c;…

Adobe全新AI工具引关注,Adobe firefly助力创作更高效、更有创意

原标题&#xff1a;Adobe全新AI工具引关注&#xff0c;Adobe firefly&#xff08;萤火虫&#xff09;助力创作更高效、更有创意。 以ChatGPT为首的生成式AI、AIGC等工具的战局正如火如荼的进行中..... 除了微软、百度的聊天机器人和一些初创公司的AI画图工具令人惊艳&#xff…

Greenplum数据库执行器——PartitionSelector执行节点

为了能够对分区表有优异的处理能力&#xff0c;对于查询优化系统来说一个最基本的能力就是做分区裁剪partition pruning&#xff0c;将query中并不涉及的分区提前排除掉。如下执行计划所示&#xff0c;由于单表谓词在parititon key上&#xff0c;在优化期间即可确定哪些可以分区…

003:Mapbox GL设定不同的投影方式

第003个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中设定不同的投影方式 。默认情况下为Mercator投影,或者设置为null或者undefined时候,显示为Mercator投影。 直接复制下面的 vue+mapbox源代码,操作2分钟即可运行实现效果 文章目录 示例效果配置方式示例源…

【分享】维格表集成易聊实现线索自动化,减少流失率

公司•介绍 北京某职业教育公司专注行业发展、国际就业、留学、移民咨询。秉承专业性至上的原则&#xff0c;与行业内专家、高等学府以及产业集团合作&#xff0c;并邀请各领域专家组建了强大的专委会团队&#xff0c;为公司的业务开展提供专业性支持。 客户•遇到的问题 作为…

【Java面试八股文宝典之MySQL篇】备战2023 查缺补漏 你越早准备 越早成功!!!——Day23

大家好&#xff0c;我是陶然同学&#xff0c;软件工程大三即将实习。认识我的朋友们知道&#xff0c;我是科班出身&#xff0c;学的还行&#xff0c;但是对面试掌握不够&#xff0c;所以我将用这100多天更新Java面试题&#x1f643;&#x1f643;。 不敢苟同&#xff0c;相信大…

用Spring Doc代替Swagger

1 OpenApi OpenApi 是一个业界的 API 文档标准&#xff0c;是一个规范&#xff0c;这个规范目前有两大实现&#xff0c;分别是&#xff1a; SpringFoxSpringDoc 其中 SpringFox 其实也就是我们之前所说的 Swagger&#xff0c;SpringDoc 则是我们今天要说的内容。 OpenApi 就…

苹果智能戒指专利曝光,Find My技术加持不易丢

根据美国商标和专利局&#xff08;USPTO&#xff09;公示的清单&#xff0c;苹果近日获得了一项“智能戒指”相关的设计专利&#xff0c;编号为“US 11625098 B2”。 这款智能戒指专利主要服务于增强现实&#xff08;AR&#xff09;或者虚拟现实&#xff08;VR&#xff09;场…

leetcodeTmp

39. 组合总和 39. 组合总和 DFS排列&#xff1a;每个元素可选0次&#xff0c;1次以及多次 public List<List<Integer>> combinationSum(int[] candidates, int target) {//Arrays.sort(candidates);//注释了也能通过this.candidates candidates;ans.clear();co…

Omniverse Replicator 入门

OmniverseReplicator入门 Omniverse Replicator 作为 Omniverse Kit 扩展创建&#xff0c;并通过 Omniverse Code 方便地分发。 要使用复制器&#xff0c;您需要下载可在此处找到的 Omniverse 启动器。 有关 Omniverse 启动器的更多详细信息&#xff0c;请查看此视频。 使用…

kafaka学习

kafaka 消息队列&#xff1a;通常用来解决一个进程内&#xff0c;多线程环境下&#xff0c;资源竞争的问题&#xff1b;但是消息队列的锁的粒度太大了&#xff0c;需要进行拆分 消息队列中间组件 一个进程中&#xff0c;同时存在生产者、消费者、消息队列&#xff0c;在分布…

网络文件传输防止篡改-校验工具(md5sum)的使用

说明 MD5报文摘要算法&#xff08;Message-Digest Algorithm 5&#xff09;常常被用来验证网络文件传输的完整性&#xff0c;防止文件被人篡改。此算法对任意长度的信息逐位进行计算&#xff0c;产生一个二进制长度为128位&#xff08;十六进制长度就是32位&#xff09;的“指…

wordpres漏洞扫描器——wpscan

WordPress 使用PHP语言开发的博客平台 WordPress是使用PHP语言开发的博客平台&#xff0c;用户可以在支持PHP和MySQL数据库的服务器上架设属于自己的网站。也可以把 WordPress当作一个内容管理系统&#xff08;CMS&#xff09;来使用。 WordPress是一款个人博客系统&#xff0c…