C++泛编程(4)

news2024/9/22 5:04:55

类模板高级(1)

  • 1.类模板具体化
    • 部分具体化
    • 完全具体化
  • 2.类模板与继承
    • 2.1模板类继承普通类
    • 2.2普通类继承模板类的实例化版本
    • 2.3普通类继承类模板
    • 2.4模板类继承模板类
    • 2.5模板类继承模板参数给出的类

1.类模板具体化

有了函数模板具体化的基础,学习类模板的具体化很简单。类模板具体化有两种方式,分别为部分具体化和完全具体化。假如有类模板:

template<class T1,class T2>
class AA 
{
    public:
        T1 m_a;
        T2 m_b;
        AA(T1 a,T2 b):m_a(a),m_b(b)
        {
            cout<<"类模板构造函数"<<endl;
        }
        void show();
};
template<class T1,class T2>
void AA<T1,T2>::show()
{
    cout<<m_a<<" "<<m_b<<endl;
}

这里把方法写在类外是为了更好地区分语法上的差别。这个模板的部分具体化和完全具体化有什么差别呢?

部分具体化

部分具体化是类模板特有的,它是指模板类的部分通用类型具有指定的数据类型,示例如下:

template<class T1>
class AA<T1,string>
{
    public:
        T1 m_a;
        string m_b;
        AA(T1 a,string b="ZhangSan"):m_a(a),m_b(b)
        {
            cout<<"类模板部分具体化构造函数"<<endl;
        }
        void show();
};
template<class T1>
void AA<T1,string>::show()
{
    cout<<m_a<<" "<<m_b<<endl;
}

这就是AA模板类的一个不完全具体化版本了。这个AA模板缺省了一个通用类型参数,在类外对方法进行定义时需要指出AA的两个模板参数,具体参数也不可以省略,其余不变。

完全具体化

完全具体化就是类模板完全没有通用参数,它才像是函数模板具体化,举例如下:

template<>
class AA<char,string>
{
    public:
        char m_a;
        string m_b;
        AA(char a='m',string b="ZhangSan"):m_a(a),m_b(b)
        {
            cout<<"类模板部分具体化构造函数"<<endl;
        }
        void show();
};
void AA<char,string>::show()
{
    cout<<m_a<<" "<<m_b<<endl;
}

这里有一个细节需要大家注意,我们在类外定义方法时不再需要写template标识符,但依然需要注明AA的两个具体的模板参数。
下面我们来调用一下模板类,看看调用的优先级:

int main()
{
    AA<int,int> aa(10,20);
    aa.show();
    AA<int,string> bb(10);
    bb.show();
    AA<char,string> cc('w',"LiSi");
    cc.show();
}

在这里插入图片描述
可以看到,如果满足完全具体化类的条件,会优先使用完全具体化类,如不满足,满足不完全具体化类条件优先使用不完全具体化类。只有当二者都不满足时才会使用普通的模板类。

2.类模板与继承

模板类的花样很多,因此类的继承玩法也很多。我们总结五种常用的用法,但其实只需知晓原理就行,用到的时候如果忘记了可以回来查看。

2.1模板类继承普通类

这个任务最简单,我们只需要把模板类当成普通类,写一个集成即可:

class AA
{
    public:
        int m_a;
        AA(int a):m_a(a)
        {cout<<"这里是AA的构造函数"<<endl;}
        void fun1()
        {cout<<"这里是fun1函数 "<<m_a<<endl;}
};
template<class T>
class BB:public AA
{
    public:
        T m_b;
        BB(T b,int a):AA(a),m_b(b)
        {cout<<"这里是BB的构造函数"<<endl;}
        void fun2()
        {cout<<"这里是fun2函数 "<<m_b<<endl;}
};

int main()
{
    BB<string> b("ZhangSan",10);
    b.fun1();
    b.fun2();
}
// 输出为:这里是AA的构造函数
//		  这里是BB的构造函数     
//		  这里是fun1函数 10      
//		  这里是fun2函数 ZhangSan

与普通的类继承一样,把基类的构造函数安排好就可以了。

2.2普通类继承模板类的实例化版本

实例化的类模板和普通类没有区别,继承方法也是一样。我们对上例中两个类稍作调整:

template<class T>
class BB
{
    public:
        T m_b;
        BB(T b):m_b(b)
        {cout<<"这里是BB的构造函数"<<endl;}
        void fun2()
        {cout<<"这里是fun2函数 "<<m_b<<endl;}
};
class AA:public BB<string>
{
    public:
        int m_a;
        AA(int a,string b):BB(b),m_a(a)
        {cout<<"这里是AA的构造函数"<<endl;}
        void fun1()
        {cout<<"这里是fun1函数 "<<m_a<<endl;}
};
int main()
{
    AA b(10,"ZhangSan");
    b.fun1();
    b.fun2();
}
// 输出为:这里是BB的构造函数
//		  这里是AA的构造函数     
//		  这里是fun1函数 10      
//		  这里是fun2函数 ZhangSan

继承一个实例化的模板类和继承普通类没有区别,但这种继承也并不实用。

2.3普通类继承类模板

继承模板类的一个具体化版本并不实用,我们更多用到的是继承模板类本身,以保留模板类的特性。但想做到这样,也得给子类加上模板头:

template<class T>
class BB
{
    public:
        T m_b;
        BB(T b):m_b(b)
        {cout<<"这里是BB的构造函数"<<endl;}
        void fun2()
        {cout<<"这里是fun2函数 "<<m_b<<endl;}
};
template<class T>
class AA:public BB<T>
{
    public:
        int m_a;
        AA(int a,T b):BB<T>(b),m_a(a)
        {cout<<"这里是AA的构造函数"<<endl;}
        void fun1()
        {cout<<"这里是fun1函数 "<<m_a<<endl;}
};
int main()
{
    AA<string> b(10,"ZhangSan");
    b.fun1();
    b.fun2();
}
// 输出为:这里是BB的构造函数
//		  这里是AA的构造函数     
//		  这里是fun1函数 10      
//		  这里是fun2函数 ZhangSan

AA现在也被迫成了模板类,所以我们实例化AA的时候需要指定模板通用类型。此外,我们在子类AA的构造函数中需要使用BB的构造函数,也应当注意语法的变化。这种继承也是比较常用的。

2.4模板类继承模板类

有了普通类继承模板类的基础,模板类继承模板类就非常好理解。回到上例,假如AA(子类)本身就是一个模板类,通用参数的名字是U,我们把基类的通用参数加到template里就可以了,其他的语法基本不需要改:

template<class T>
class BB
{
    public:
        T m_b;
        BB(T b):m_b(b)
        {cout<<"这里是BB的构造函数"<<endl;}
        void fun2()
        {cout<<"这里是fun2函数 "<<m_b<<endl;}
};
template<class U,class T>
class AA:public BB<T>
{
    public:
        U m_a;
        AA(U a,T b):BB<T>(b),m_a(a)
        {cout<<"这里是AA的构造函数"<<endl;}
        void fun1()
        {cout<<"这里是fun1函数 "<<m_a<<endl;}
};
int main()
{
    AA<int,string> b(10,"ZhangSan");
    b.fun1();
    b.fun2();
}
// 输出为:这里是BB的构造函数
//		  这里是AA的构造函数     
//		  这里是fun1函数 10      
//		  这里是fun2函数 ZhangSan

2.5模板类继承模板参数给出的类

这是一种很新奇的玩法,简单地说就是基类是不确定的,具体继承谁要在调用时才会确定,很像是容器嵌套:

class AA
{
    public:
        int m_a;
        AA(int a):m_a(a)
        {cout<<"这里是AA的构造函数"<<endl;}
        void fun1()
        {cout<<"这里是fun1函数 "<<m_a<<endl;}
};

template<class T>
class BB
{
    public:
        T m_b;
        BB(T b):m_b(b)
        {cout<<"这里是BB的构造函数"<<endl;}
        void fun2()
        {cout<<"这里是fun2函数 "<<m_b<<endl;}
};


template<class U,class T>
class CC:public U
{
    public:
        CC(T a):U(a)
        {cout<<"这里是CC的构造函数"<<endl;}
        void fun3()
        {cout<<"这里是fun3函数 "<<endl;}
};
int main()
{
    CC<AA,int> c1(15);
    c1.fun1();c1.fun3();
    cout<<endl;
    CC<BB<string>,string> c("LiSi");
    c1.fun1();c1.fun3();
}

这段代码会有些难度,大家可以自己写写试试。另外提示一点,template里定义的参数只有在当前的模板类起作用,后面的模板里即使有重名也不会影响代码。换句话说假如AA类用T1表示通用类型,CC类用T2,T3表示通用数据类型效果实际和这个例子上是一样的,不要被重名迷惑了。

这节我们具体学习了类模板的具体化和几种常用的继承,语法并不困难,我们也只需要理解原理,记不住的话后面用到的时候查一下就好。

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

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

相关文章

STL算法(中)

常用排序算法 sort 功能描述&#xff1a; 对容器内元素进行排序 函数原型&#xff1a; sort(iterator beg, iterator end, _Pred) ; // 按值查找元素&#xff0c;找到返回指定位置迭代器&#xff0c;找不到返回结束迭代器位置 // beg 开始迭代器 // end 结束迭代器 …

1-3 mininet中使用python API直接拓扑定义以及启动方式对比

作为SDN网络中搭建拓扑非常重要的仿真平台&#xff0c;我们可以使用mininet默认的库内拓扑文件&#xff0c;也可以使用python语言进行自定义拓扑。使用python进行拓扑定义时&#xff0c;不同的定义方式将导致其启动的方式由所不同。 一、采用最原始的命令启动方式&#xff1a; …

Redis——事件

Redis服务器是一个事件驱动程序&#xff0c;服务器需要处理以下两种事件&#xff1a; 文件事件(file event)&#xff1a;Redis服务器通过套接字与客户端(或者其他Redis服务器)进行连接&#xff0c;而文件事件就是服务器对套接字操作的抽象(linux下一切皆文件&#xff0c;返回的…

TP框架 之think-auth权限认证

一、安装think-auth composer require 5ini99/think-auth二、数据表 -- ---------------------------- -- think_auth_rule&#xff0c;规则表&#xff0c; -- id:主键&#xff0c;name&#xff1a;规则唯一标识, title&#xff1a;规则中文名称 status 状态&#xff1a;为1正常…

【日志记录】——单片机可执行文件合并

一&#xff1a;需求场景 现在有一片单片机&#xff0c;执行程序包括自定义boot和应用程序app, 在将打包好的固件给到生产时有以下问题&#xff0c;由于要通过jlink烧录boot&#xff0c;然后上电启动boot&#xff0c;通过boot烧录初始化程序&#xff0c;过程过于复杂&#xff0…

基于ESP-WROOM-32的双串口通信并显示到OLED显示屏上

目录 开发板引脚图 Arduino环境配置1.ESP32开发版下载2.Arduino开发板选择 -> ESP32 Dev Module3.安装驱动库 接线图Arduino代码现象演示 开发板 ESP-WROOM-32 引脚图 Arduino环境配置 1.ESP32开发版下载 选择 esp32 by Espressif Systems 2.Arduino开发板选择 -> E…

一文读懂「四大主流计算芯片 CPU、GPU、ASIC、FPGA」特点和场景

纵观人类历史&#xff0c;从结绳计数、木制计数到巴比伦的粘土板上的刻痕&#xff0c;再到中国古代的算盘&#xff0c;社会生产力的提高与当时所采用的计算工具密切相关。计算工具能力越强&#xff0c;就能大幅缩短人类解决复杂问题的时间&#xff0c;社会生产力水平自然就会越…

微信小程序解决华为手机保存图片到相册失败

1.新增隐私设置 2.优化代码 新增uni.authorize判断 _saveCode() {let that this;console.log(点击了保存图片)console.log(this.result)uni.authorize({scope: scope.writePhotosAlbum,success(e) {console.log(e)if (this.result ! "") {uni.saveImageToPhotosAlb…

RCS系统之:界面设计

RCS Floor Manager设计的主要目的&#xff1a; 实时监控机器人状态实时查看货架状态查看机器人任务状态查看捡货站的任务状态地图的状态信息其他元素&#xff0c;如打包机&#xff0c;机械臂的状态动态的编辑地图元素信息等等 有兴趣的可以留言一起交流下

[office] Excel2007在工作簿中创建区域名称 #职场发展#经验分享

Excel2007在工作簿中创建区域名称 Excel 提供了几种不同的方法来创建区域名称。但在开始之前&#xff0c;必须注意关于可接受内容的重要规则: 名称不能含有空格。可以用一个下划线字符来代替空格(如Annual Total ) 。 可以使用字母和数字的任意组合&#xff0c;但是名称必须以…

Redis + Lua 实现分布式限流器

文章目录 Redis Lua 限流实现1. 导入依赖2. 配置application.properties3. 配置RedisTemplate实例4. 定义限流类型枚举类5. 自定义注解6. 切面代码实现7. 控制层实现8. 测试 相比 Redis事务&#xff0c; Lua脚本的优点&#xff1a; 减少网络开销&#xff1a;使用Lua脚本&…

C++ STL精通之旅:向量、集合与映射等容器详解

目录 常用容器 顺序容器 向量vector 构造 尾接 & 尾删 中括号运算符 获取长度 清空 判空 改变长度 提前分配好空间 代码演示 运行结果 关联容器 集合set 构造 遍历 其他 代码演示 运行结果​编辑 映射map 常用方法 构造 遍历 其他 代码演示1​编…

搜索与图论(一)(深搜,广搜,树与图的存储遍历,拓扑排序)

一、DFS 往深里搜&#xff0c;搜到叶子结点那里&#xff0c;回溯&#xff0c;到可以继续到叶子结点深搜的位置。 1、回溯一定要恢复现场 2、定义一个与当前递归层数有关的终止条件&#xff08;题目要求的东西&#xff09; 3、每层都用循环判断是否存在可以dfs的路 输出数字…

PbootCMS采集插件使用教程

这篇Pboot采集教程教你使用PbootCMS采集插件&#xff0c;自动批量采集网页文章数据&#xff0c;并发布到PbootCMS系统&#xff0c;快速丰富网站的内容。 1. 下载并安装PbootCMS采集插件 1-1&#xff09;PbootCMS采集插件免费下载&#xff1a;Pboot采集插件-PbootCMS发布模块下…

「Mybatis实战五」:Mybatis核心文件详解 - MyBatis常用配置environments、properties

一、MyBatis核心配置文件层级关系 ​ 本文代码在 Mybatis初体验&#xff1a;一小时从入门到运行你的第一个应用 所构建的基础代码结构之上&#xff0c;进行修改。 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下&#xff1a; 二…

什么是大小端字节序存储?如何用代码判断当前的机器是大端字存储还是小端存储?

目录 什么是大端字节序存储与小端字节序存储 为什么会有大端和小端之分&#xff1f; 用代码判断当前机器是大端存储还是小端存储 什么是大端字节序存储与小端字节序存储 1.字节序&#xff1a;以字节为单位&#xff0c;讨论存储顺序 2.大端字节序存储&#xff1a;高位在低地…

C和C++面试--看的不多只看一篇

C和C面试 1. 语言基础1.1 C和C有什么区别&#xff1f;1.2 a和&a有什么区别&#xff1f;1.3 #define和const区别&#xff1f;&#xff08;编译阶段、安全性、内存占用等&#xff09;1.4 inline函数1.5 对于⼀个频繁使⽤的短⼩函数&#xff0c;应该使⽤什么来实现&#xff1f…

【C语言】三子棋游戏实现代码

目录 1.三子棋代码功能介绍 2.三子棋游戏实现步骤 ①打印菜单栏 ②判断是否进入三子棋游戏 ③三子棋游戏基本函数实现 &#xff08;1&#xff09;清空&#xff08;初始化&#xff09;棋盘函数实现 &#xff08;2&#xff09;打印棋盘函数实现 &#xff08;3&#xff0…

【HTML】MDN

文章目录 一、html元素1.1 <a>1.2 <abbr>1.3 <address>1.4<area>1.5 <article>1.6 <aside>1.7 <audio>1.8 <b>1.9 <base>1.10<bdi>1.11 <bdo>1.12 <blockquote>1.13 <body>1.14 <br>1.15…

计组学习笔记2024/2/4

1.计算机的发展历程 2.计算机硬件的基本组成 存储器 -> 就是内存. 3.各个硬件的部件 寄存器 -> 用来存放二进制数据. 各个硬件的工作原理视频留白,听完后边课程之后再来理解理解. 冯诺依曼计算机的特点: 1.计算机由五大部件组成 2.指令和数据以同等地位存于存储器,…