C++ 函数模板和类模板

参考视频:C++类模板_哔哩哔哩_bilibili

遗留问题:编译器怎么处理函数模板和类模板

目录

一、为什么会有函数模版?函数模板是为了解决什么问题?

二、函数模板的概念

三、函数模版的使用

四、函数模板的特化

五、类模板的概念

六、类模板的使用

七、类模板的特化

八、类模板的偏特化


一、为什么会有函数模版?函数模板是为了解决什么问题?

     函数模板是为了减少重复代码,是整合多个函数的函数体相同而区别只在参数类型不同的代码冗余的情况。不用函数模板前,多个函数的参数类型不同,但函数体相同,导致重复代码较多。有了函数模板,只需要一份函数体一份代码就可以实现原来需要几个函数体才实现的功能,例如不使用函数模板时,要分别对int、char等类型的两个数据做是否相等判断,需要定义多个函数:

bool isEqual( int nA,  int nB)
{return nA == nB;
}bool isEqual(char cA, char cB)
{return cA == cB;
}int main()
{int nA = 10;int nB = 20;char cA = 'A';char cB = 'B';std::cout << isEqual(nA, nB)<< std::endl;std::cout << isEqual(cA, cB) << std::endl;return 0;
}

 可见重载的两个函数的函数体实现一样,函数体代码重复,下面是使用函数模板的代码:

#include <iostream>
//使用模板代替原来的多个函数
template<typename T>
bool isEqual(T tA, T tB)
{return tA == tB;
}int main()
{
//变量以匈牙利命名法命名int nA = 10;int nB = 20;char cA = 'A';char cB = 'B';
//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout << isEqual(nA, nB)<< std::endl;
//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout << isEqual(cA, cB) << std::endl;return 0;
}

二、函数模板的概念

       函数模板是用于生成函数的模板。在编译阶段,编译器会根据函数模板的使用情况(例如上面的isEqual(nA, nB)、isEqual(cA, cB)创建出函数名相同,参数类型由编译器判断的若干函数。通过函数模板创建的函数拥有相同的函数体,只是函数的参数类型不同。

三、函数模版的使用

        每当在一个编译单元(经过预处理的.cpp文件)中使用了函数模版,则必须在该编译单元中给出函数模版的定义(要是把函数模板声明写在.h文件,函数模板声明写在.cpp文件,然后在使用函数模板时只使用include 包含函数模板的头文件,不给出函数模板的定义,那么编译会报无法解析的外部符号错误)。因此,为了避免在每个编译单元都定义函数模板,建议在头文件中对函数模板进行声明定义(即将函数模板的声明和定义都写在一个头文件中,然后在需要使用函数模板的地方加上该头文件)。

   函数模版的声明:

template<typename T>返回类型 函数名(参数列表);其中T表示任意类型,参数的类型和返回类型都可以指定为T

函数模版的定义

template<typename T,..>  //可指定多个泛型
返回类型 函数名(参数列表)
{//函数体
}

将一、为什么会有函数模版?函数模板是为了解决什么问题?这一节中的函数模板的声明和定义写在isEqualFunc.h头文件中再使用:

#ifndef ISEQUALFUNC_H
#define ISEQUALFUNC_H
//函数模板声明
template<typename T>
bool isEqual(T tA, T tB);//函数模板定义
template<typename T>
bool isEqual(T tA, T tB)
{return tA == tB;
}#endif // ISEQUALFUNC_H
//这是main.cpp
#include "isEqualFunc.h"
#include <iostream>int main()
{//变量以匈牙利命名法命名int nA = 100111111;int nB = 111111;char cA = 'A';char cB = 'A';//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout << isEqual(nA, nB)<< std::endl;//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout << isEqual(cA, cB) << std::endl;return 0;
}

四、函数模板的特化

函数模板特化是指在实例化函数模板时,对特定类型的实参进行特殊的处理,即当实参为特定类型时,通过函数模板生成的函数会有不同的函数体。

特化时需要为函数模板添加新的定义,方式如下:

template<>
返回类型 函数名<特定的参数类型>(参数列表)
{//函数体
}

在上面的例子中,对于char*类型的字符串,使用上面的函数模板无法对字符串正确判断是否相等,因为字符串比较不是直接比较指针是否相等,而要调用strcmp函数判断,对上面的例子就需要对函数模板进行特化

#ifndef ISEQUALFUNC_H
#define ISEQUALFUNC_H
#include <string.h>
//函数模板声明
template<typename T>
bool isEqual(T tA, T tB);//函数模板定义
template<typename T>
bool isEqual(T tA, T tB)
{return tA == tB;
}//函数模板的特化
template<>
bool isEqual< char* >( char* szA,  char* szB)
{return strcmp(szA, szB) == 0;
}#endif // ISEQUALFUNC_H
//这是main.cpp
#include "isEqualFunc.h"
#include <iostream>int main()
{//变量以匈牙利命名法命名int nA = 100111111;int nB = 111111;char cA = 'A';char cB = 'A';char szA[4] = "AAA";char szB[4] = "AAA";// 编译器会怎么处理函数模板和特化?待参考https://blog.csdn.net/zgaoq/article/details/85232968//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(int, int);std::cout << isEqual(nA, nB)<< std::endl;//编译期间,编译器根据实参类型和模板函数生成函数bool isEqual(char, char);std::cout << isEqual(cA, cB) << std::endl;std::cout << isEqual(szA, szB) << std::endl; //判断字符串是否相等return 0;
}

五、类模板的概念

类模板是用于生成类的模板。在编译阶段,编译器会根据类模板的使用情况创建出仅部分成员数据类型和部分成员函数的参数类型不同,其他完全相同的若干类。

通过类模板的这些特性我们可以尝试写出用于存放不同类型数据的容器。

六、类模板的使用

类模板的声明格式:

template<typename T,...>
class 类名
{//成员
};

类模板的成员函数定义如下,一般类模板的定义也应该写在头文件中: 

template<typename T,...>
返回类型 类名<T,...>::成员函数名(形参列表)
{//函数体
}

下面是一个例子,这个例子定义了一个MyArray的类模板,其中数据成员是数组,通过泛型T达到可定义各种类型数组的目的,而所有对这个数组的操作函数都相同,这样就不用针对不同类型的数组,定义不同的类,达到了复用代码即减少重复代码的目的:

//这是myArray.h
#ifndef MYARRAY_H
#define MYARRAY_H
#include <iostream>
constexpr int m_nMaxLen = 20;template <typename T>
class MyArray
{
public:MyArray():size(0){}//添加数据bool addData(T value);//删除数据bool deleteData(T value);//获取数据T getData(int nIndex);void print(){for(int i = 0; i < size; i++){std::cout << data[i] << std::endl;}}
private:T data[m_nMaxLen];int size;
};template<typename T>
bool MyArray<T>::addData(T value)
{if(size == m_nMaxLen){return false;}data[size] = value;size++;return true;
}template<typename T>
bool MyArray<T>::deleteData(T value)
{if(size == 0){return false;}int nDataIndex = -1;for(int i = 0; i < size; i++){if(data[i] == value){nDataIndex = i;break;}}if(nDataIndex == -1){std::cout<< "找不到该数据!"  << std::endl;return false;}else{for(int i = nDataIndex; i < size -1; i++){data[i] = data[i+1];  //往前移动后面的数据,即可以删除该数据}size --;}return true;
}template<typename T>
T  MyArray<T>::getData(int nIndex)
{if(nIndex >= 0 && nIndex < size){return data[nIndex];}else{return (T)0;}
}#endif // MYARRAY_H
//这是main.cpp
#include "myarray.h"
#include <iostream>
int main()
{std::cout <<"----int begin----" << std::endl;MyArray<int> intData;for(int i = 1; i <= 10; i++){intData.addData(i);}intData.print();std::cout <<"--------" << std::endl;intData.deleteData(11);std::cout <<"--------" << std::endl;intData.print();std::cout << intData.getData(0) << std::endl;std::cout <<"----int end----" << std::endl;std::cout <<"----char begin----" << std::endl;MyArray<char> charData;for(int i = 1; i <= 10; i++){charData.addData('A'+ i);}charData.print();std::cout <<"--------" << std::endl;charData.deleteData('B');std::cout <<"--------" << std::endl;charData.print();std::cout << charData.getData(1) << std::endl;std::cout <<"----char end----" << std::endl;return 0;
}

七、类模板的特化

类模板的特化是在实例化类模板时,对特定类型的泛型进行特殊的处理,即用户指定所有特定类型的类模板时,通过特化类模板生成的类可能与其他类有完全不同的结构。

特化类模板是需要对整个类模板进行声明定义:

template<>
class 类名<指定类型,指定类型,...>
{
//类成员
};

这里对第六节中的例子添加特化:

#ifndef MYARRAY_H
#define MYARRAY_H//....其他代码不变//对特定泛型的类的成员函数进行特化
template<>
MyArray<char>::MyArray()
{std::cout<< "MyArray<char>::MyArray()" << std::endl;
}//对特定泛型的类进行特化
//这里例子可能不太恰当,只是展示如何对特定类型的类进行特化
template<>
class MyArray<float>
{public:MyArray();private:float data;
};MyArray<float>::MyArray()
{std::cout<< "MyArray<float>::MyArray()" << std::endl;
}#endif // MYARRAY_H

八、类模板的偏特化

偏特化和特化类似,只是特化会指定所有的泛型,而偏特化只指定部分泛型。

偏特化类模板需要对整个类模板进行声明定义:

template <typename T,...不需特化的泛型...>
class 类名<指定类型,...不需特化的泛型名,...>
{//类成员;
}

例子:

#ifndef PAIR_H
#define PAIR_H
#include <iostream>
template<typename T1, typename T2>
class Pair
{
public:Pair();
private:T1 m_first;T2 m_second;
};template<typename T1, typename T2>
Pair<T1, T2>::Pair()
{std::cout << "Pair<T1, T2>::Pair()" << std::endl;
}//偏特化
template<typename T2>
class Pair<char, T2>
{
public:Pair();
private:char first;T2 second;
};template<typename T2>
Pair<char, T2>::Pair()
{std::cout << "Pair<char, T2>::Pair()" << std::endl;
}#endif // PAIR_H
//这是main.cpp
#include <iostream>
#include "Pair.h"
int main()
{Pair<int, int> pNn;Pair<char, int> pCn;return 0;
}

运行结果:

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

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

相关文章

基于ssm+vue+uniapp的英语学习交流平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

排序算法之桶排序

title: 桶排序 date: 2024-7-25 18:58:19 0800 categories: 排序算法 tags:排序算法桶排序 description: 桶排序&#xff08;bucket sort&#xff09;是分治策略的一个典型应用。它通过设置一些具有大小顺序的桶&#xff0c;每个桶对应一个数据范围&#xff0c;将数据平均分配…

Qt—Qtcreator中自定义类时,下拉菜单中没有出现要继承的Qt类

问题描述&#xff1a;Qtcreator中自定义类时&#xff0c;下拉菜单中没有出现要继承的Qt类 这里我想要继承 QLineEdit 类&#xff0c;但是在这个下拉菜单中没有找到 我认为这个是qtcreator版本的问题&#xff0c;因为我直接去 #include 是可以找到这个类的 直接创建出来的类中…

Python Flask 与 Node.js Express

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 构建 Web 应用程序时&#xff0c;选择正确的框架对于性能和可扩展性至关重要。Python 的 Flask 和 Node.js 的 Express 是两种流行的选择&#xff0c;它们根据项目…

重启人生计划-勇敢者先行

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 如果你觉得这个【重启人生…

Go语言 Defer(延迟)

本文主要内容为Go语言中defer(延迟)介绍及应用文件读取使用defer的示例。 目录 定义 应用场景 代码示例 改为匿名函数 总结 定义 延迟&#xff1a;关键字&#xff0c;可以用于修饰语句、函数&#xff0c; 确保这条语句可以在当前栈退出的时候执行。 应用场景 1.一般用于…

SQL Server端口设置完整详细步骤

​ 大家好&#xff0c;我是程序员小羊&#xff01; 前言&#xff1a; 前面是对SQLserver服务器一些介绍&#xff0c;不想了解的可直接点击目录跳入正题&#xff0c;谢谢&#xff01;&#xff01;&#xff01; SQL Server 是由微软公司开发的关系数据库管理系统 (RDBMS)。它主要…

c++33 一级指针 字符串

拿到buf5 内存的首地址来释放内存 所以buf5不可改变 为了保证局部变量内存的局部性 字符串指针1级 如果没有拷入\0 则b还为一个数组 字符串拷贝函数 主调函数分配到内存 把g后面的内存变成\ 0 所以就改变了内存空间 考虑&#xff1a;主调用函数分配内存供被调用函数…

Python爬虫开发:BeautifulSoup、Scrapy入门

在现代网络开发中&#xff0c;网络爬虫是一个非常重要的工具。它可以自动化地从网页中提取数据&#xff0c;并且可以用于各种用途&#xff0c;如数据收集、信息聚合和内容监控等。在Python中&#xff0c;有多个库可以用于爬虫开发&#xff0c;其中BeautifulSoup和Scrapy是两个非…

FL Studio 24.1.1.4239中文破解版的安装激活详细教程

在数字音乐制作领域&#xff0c;FL Studio一直以其强大的功能和用户友好的界面而备受赞誉。随着技术的不断进步和音乐制作需求的日益增长&#xff0c;FL Studio 21.2.3的发布无疑为音乐创作者们带来了更为广阔的创作空间和更高效的制作工具。本文旨在深入探讨FL Studio 21.2.3的…

关于k8s的pvc存储卷

目录 1.PVC 和 PV 1.1 PV 1.2 PVC 1.3 StorageClass 1.4 PV和PVC的生命周期 2.实战演练 2.1 创建静态pv 2.2 创建动态pv 3.总结 1.PVC 和 PV 1.1 PV PV 全称叫做 Persistent Volume&#xff0c;持久化存储卷。它是用来描述或者说用来定义一个存储卷的&#xff0c;…

2024 年 7 月公链行业研报:市场波动中 Solana 表现抢眼,Layer 2 竞争白热化

作者&#xff1a;Stella L (stellafootprint.network) 数据来源&#xff1a;Footprint Analytics 公链 Research 页面 7 月份&#xff0c;加密货币市场表现活跃&#xff0c;波动幅度较大&#xff0c;这一现象映射了全球金融市场的整体趋势。现货以太坊 ETP 在美国的上市&…

k8s 部署RuoYi-Vue-Plus之minio搭建

1.直接部署一个pod 需要挂载存储款, 可参考 之前文章设置 https://blog.csdn.net/weimeibuqieryu/article/details/140183843 2.部署yaml 创建部署文件 minio-deploy.yaml apiVersion: v1 kind: PersistentVolume metadata:name: minio-pvnamespace: ruoyi #使用ns ruoyi s…

无字母数字webshell之命令执行

目录 1.源码 2.题目解析 3.利用方法 3.1 PHP7下如何实现 3.2PHP5下如何实现 3.2.1 shell下可以利用. 来执行任意脚本 3.2.2 Linux文件名支持用glob通配符代替 1.题目源码 <?php if(isset($_GET[code])){$code $_GET[code];if(strlen($code)>35){die(&q…

本地phpstudy部署算命系统,用户端是H5页面,支持微信支付宝支付,支持微信支付宝登录

算命系统本地部署教程 0. 技术架构1. 启动Apache、MySQL服务2. 创建前台和后台两个网站3. Navicat连接数据库4. 登录后台是长这个样子5. 登录前台登录样子6. 代码结构是 0. 技术架构 前端&#xff1a;HTMLCSSJquery 后端&#xff1a;PHP 数据库&#xff1a;MySQL 1. 启动Ap…

C# OnnxRuntime部署LivePortrait实现快速、高质量的人像驱动视频生成

目录 效果 说明 项目 模型信息 代码 下载 效果 LivePortrait实现快速、高质量的人像驱动视频生成 说明 官网地址&#xff1a;https://github.com/KwaiVGI/LivePortrait 代码实现参考&#xff1a;https://github.com/hpc203/liveportrait-onnxrun 模型下载&#xff1a;…

Haproxy简介及配置详解

一、Haproxy简介 官网&#xff1a; 企业版网站: https://www.haproxy.com 社区版网站: http://www.haproxy.org github: https://github.com/haprox Haproxy是法国人Willy Tarreaus开发的一款开源软件&#xff0c;能够提供高性能、负载均衡以及基于HTTP和TCP应用个代理&…

python-flask-上传多个文件并存储

本地环境&#xff1a;win10 / centos6 &#xff0c; python3 flask入门看这里&#xff1a; ↓ python-flask结合bootstrap实现网页小工具实例-半小时速通版_bootstrap flask-CSDN博客 https://blog.csdn.net/pxy7896/article/details/137854455 动态添加和删除表格中的行&…

【实用工具】Stirling-PDF: 优质开源的PDF处理工具/编辑工具-含入门安装教程

文章目录 项目简介功能展示Page Operations 页面操作Conversion Operations 转换操作Security & Permissions 安全与权限Other Operations 其他业务 如何安装并使用Docker RunDocker Compose 项目简介 这是一款使用 Docker 的基于本地托管网络的强大 PDF 操作工具。它能让…

头狼择校小程序

综述介绍 头狼择校&#xff0c;是头狼择™高校的简称&#xff0c;我们专注高校、大学的择校。倡导先嗅就业再择校&#xff0c;是预约工具和对话平台。帮您嗅招办、嗅教授、嗅学姐&#xff0c;预约择校有关的老师、顾问&#xff0c;助力考大学和考研的“双考”学生及家长了解就…