C++初阶模板

介绍:

        我们先认识以下C++中的模板。模板是一种编程技术,允许程序员编写与数据类型无关的代码,它是一种泛型编程的方式,可以用于创建可处理多种数据类型的函数或类,也就是说泛型编程就是编写与类型无关的通用代码,是代码复用的一种手段,而模板是泛型编程的基础。其中,模板分为函数模板和类模板。


函数模板:

        函数模板是一种通用的函数定义,可以接受多种类型作为输入,并生成对应的特定类型函数。

格式:

        template<typename T1, typename T2, .... , typename Tn>

        template 返回值类型 函数名(参数列表){}

//定义一个可以实现多种类型交换的函数

template<typename T>
void Swap(T& left, T& right)
{
    T temp = left;
    left = right;
    right = temp;
}

        注意:上面的typename是用来定义模板参数的关键字,这可使用class,我们目前可先认为class与typename无任何区别,但是这里不能使用struct来代替。

函数模板的工作原理:

        这里要说明的是函数模板是一个 “ 蓝图 ”,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。

        在编译器编译阶段,当调用函数模板时,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,其它类型也是如此。

        注意:函数模板并不会为每个可能的类型组合生成函数,后文会对齐深入讲解。

函数模板的实例化:

        函数模板根据传入的实参类型生成特定类型的函数,然后调用这些函数,此过程称为函数模板的实例化。其中,模板参数实例化分为:隐式实例化和显式实例化。

        隐式实例化:让编译器根据实参推演模板参数的实际类型。

template<class T>
T Add(const T& left, const T& right)
{
    return left + right;
}
int main()
{
    //隐式实例化
    Add(1, 2);
    Add(1.2, 1.3);
    return 0;
}

        显式实例化:在函数名后的<>中指定模板参数的实际类型。

template<class T>
T Add(const T& left, const T& right)
{
    return left + right;
}
int main()
{
    int a = 10;
    double b = 20.0;
    //显式实例化
    Add<int>(a, b);
    return 0;
}

        注意:当进行类型转换时,如果编译器没有找到与实参类型匹配的函数模板,它会自动进行隐式实例化,如果还无法确定实例化的类型,就会报错。    

        下面我们观察以下代码的问题:

template<class T>
T Add(const T& left, const T& right)
{
    return left + right;
}
template<typename T1, typename T2>
T1 add(const T1& left, const T2& right)
{
    return left + right;
}
int main()
{
    Add(1, 1.2);//系统报错
    Add(1, (int)1.2);//强制转换,运行正常
    Add<int>(1, 1.2);//显示实例化,运行正常

    add(1, 1.2);//参数匹配,运行正常
    return 0;
}

        以上语句不能通过编译是因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
通过实参1将T推演为int,通过实参1.2将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型,进而报错。

        注意:在模板中,编译器一般不会进行类型转换操作。

        解决以上方法有三种:1. 直接强制转化    2. 使用显式实例化     3. 设置多个模板参数

模板函数与非模板函数:

        一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数,当调用时,如果其他条件都相同,会优先调用非模板函数。如果模板可以产生一个具有更好匹配的函数,那么将选择模板函数。

int Add(int left, int right)
{
    return left + right;
}
template<class T>
T Add(T left, T right)
{
    return left + right;
}
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
    return left + right;
}
int main()
{
    Add(1, 2); //调用非模板函数
    Add<int>(1, 2); //显示实例化,调用模板函数

    Add(1, 2); //与非函数模板类型完全匹配,调用非函数模板
    Add(1, 2.0); //模板函数可以生成更加匹配的版本,调用函数模板
    return 0;
}

        这里再强调一次,模板函数不允许自动类型转换,但普通函数可以进行自动类型转换。


类模板:

        格式如下:

template<class T1, class T2, ..., class Tn>
class 类模板名
{
    ..........
};

        类模板的实例化:类模板的实例化与函数模板的实例化不同,类模板的实例化需要在类模板名字后跟 “ <> ”,然后将实例化的类型放在 “ <> ” 中即可。

template<class T>

class Stack
{
public:
    Stack(int capacity = 4)
    {
        cout << "Stack(int capacity = 4)" << endl;
        _a = new T[capacity];//这里需要用到T,所以不能直接实例化int*或double*
        _top = 0;
        _capacity = capacity;
    }
    ~Stack()
    {
        cout << "~Stack()" << endl;
        delete[] _a;
        _a = nullptr;
        _top = 0;
        _capacity = 0;
    }
    T* _a;
    int  _top;
    int  _capacity;
};
int main()
{
    //显示实例化
    Stack<int> st1;
    cout << typeid(st1._a).name() << endl;//输出int*,因为 T* _a
    Stack<double> st2;  
    cout << typeid(st2._a).name() << endl;//输出double*,因为 T* _a
    return 0;
}

        注意:类模板名字不是真正的类,而实例化的结果才是真正的类,如下:

Stack<int> st1;  //Stack只是类名,Stack<int>才是类型
Stack<double> st2;  //Stack只是类名,Stack<double>才是类型

        当我们使用类模板对象中的成员时,要使用 “ 类型 ” 进行作用域的访问,不能使用类名。

Stack<int>.~Stack() //调用Stack<int>类型的析构函数

Stack<double>.~Stack() //调用Stack<double>类型的析构函数​​​​​​​

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

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

相关文章

多线程(补充知识)

STL库&#xff0c;智能指针和线程安全 STL中的容器是否是线程安全的? 不是. 原因是, STL 的设计初衷是将性能挖掘到极致, 而一旦涉及到加锁保证线程安全,会对性能造成巨大的影响. 而且对于不同的容器, 加锁方式的不同, 性能可能也不同(例如hash表的锁表和锁桶). 因此 STL 默认…

【LeetCode】每日一题 2023_11_25 二叉树中的伪回文路径(dfs,数组/位运算)

文章目录 刷题前唠嗑题目&#xff1a;二叉树中的伪回文路径题目描述代码与解题思路偷看大佬题解 结语 刷题前唠嗑 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 这个月第一次周末早起~ 题目&#xff1a;二叉树中的伪回文路径 题目链接&#xff1a;1457. 二…

20世纪的葡萄酒有哪些创新?

葡萄酒是用酵母发酵的&#xff0c;直到20世纪中叶&#xff0c;这一过程都依赖于自然产生的酵母。这些发酵的结果往往不一致&#xff0c;而且由于发酵时间长&#xff0c;容易腐败。 酿酒业最重要的进步之一是在20世纪50、60年代引进了地中海的纯发酵菌种酿酒酵母&#xff0c;俗称…

你要的fiddler快捷键全部在这里了,学最全的快捷键,做最快的IT程序员

一、常用三个快捷键 ctrlX :清空所有记录 CtrlF&#xff1a;查找 F12&#xff1a;启动或者停止抓包 使用 QuickExec Fiddler2 成了网页调试必备的工具&#xff0c;抓包看数据。Fiddler2自带命令行控制。 fiddler 命令行快捷键&#xff1a;ctrl q &#xff0c;然后 输入 help…

Codeforces Round #911 (Div. 2)

A.Cover in Water 题意&#xff1a; 有一个 1 n 1 \times n 1n的水池&#xff0c;里面有些格子可以加水&#xff0c;有些格子是被堵上的&#xff0c;你可以进行以下两种操作&#xff1a; 1.往一个空的格子里加水 2.移除一个有水的格子中的水&#xff0c;并将这些水添加到另…

合并区间[中等]

一、题目 以数组intervals表示若干个区间的集合&#xff0c;其中单个区间为intervals[i] [starti, endi]。请你合并所有重叠的区间&#xff0c;并返回一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间。 示例 1&#xff1a; 输入&#xff1a;intervals […

【笔记】小白学习电路维修

学习视频&#xff08;b站&#xff09;&#xff1a;从0开始学电路 从0开始学电路维修 p1 黄色长方体元件P2 故障率最高的元件p3带芯铜丝线圈是什么区分电感和变压器接入电路分析&#xff1a; p4 交流和直流分界线整流桥接线整流桥故障判断 带色环的不一定是电阻 p1 黄色长方体元…

Windows10-用户账户控制、Windows远程桌面

Windows10用户账户控制怎么设置白名单 问题引出&#xff1a; 安装低版本搜狗输入法后经常弹出用户账户控制 解决方案&#xff1a; 全局模式&#xff1a; UAC控制最早出现在Windows Vista中&#xff0c;用户帐户控制&#xff08;UAC&#xff09;是一项旨在防止对您的计算机…

web:[ZJCTF 2019]NiZhuanSiWei1

题目 点进题目&#xff0c;网页显示如下&#xff0c;需要代码审计 $_GET["text"]和$_GET["file"]来获取传入的两个参数text和file。使用isset()函数来检查$text变量是否已设置并且不为null。如果设置了并且不为null&#xff0c;则执行下面的逻辑。在下面的…

贪心算法(新坑)

贪心入门 概述&#xff1a; 贪心算法是一种在每一步选择中都采取当前最优解的策略&#xff0c;希望最终能够得到全局最优解的算法。简单来说&#xff0c;它会不断地做出局部最优的选择&#xff0c;相信通过这种选择最终能够达到全局最优。 举个例子来说明。假设你要从一个迷…

CCFCSP试题编号:202206-2试题名称:寻宝!大冒险!

一、题目 二、分析 因为藏宝图左下角位置一定是一棵树&#xff0c;所以只要把所有绿化图中每一棵树&#xff0c;与之相匹配&#xff0c;然后判断&#xff0c;是否整个藏宝图都是绿化图的一部分&#xff0c;如果是那就计数count1。所以来看&#xff0c;结果count最大也就是n(绿…

进程和线程的关系

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;JavaEE &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 进程&线程 1. 什么是进程PCB 2. 什么是…

高等数学零基础篇复习笔记

预备章 零基础高等数学入门知识 第一节 集合、运算与关系 第二节 三角函数与反三角函数 三角函数的公式 反三角函数 第三节 常见不等式及数列 划重点 第一章 函数、极限与连续 第一节 函数及函数的初等特性 特殊函数 反函数 函数的初等特性 ①有界性 ②奇偶性 偶函数图像…

高中生分科考试--座位编排系统

这个系统是帮我一同学的哥哥的做的座位编排系统&#xff0c;他是某个学校的教育从事者 基本需求&#xff1a;就是能够根据他提供的各个分科班级同学的成绩单来选择相同分科的考场编排&#xff08;按成绩高低&#xff09;&#xff0c;同时输入相应的考场数&#xff0c;和每个考…

解决git action发布报错:Input required and not supplied: upload_url

现象&#xff1a; 这个问题死活都找不到原因&#xff0c;后来打了一段调试的代码 - name: Debug Create Release Output run: | echo "Release ID: ${{ env.RELEASE_ID }}" echo "Release Upload URL: ${{ env.RELEASE_UPLOAD_URL }}" env: RELEASE_ID: ${…

docker镜像原理

什么是镜像 容器解决应用开发、测试和部署的问题&#xff0c;而镜像解决应用部署环境问题。镜像是一个只读的容器模板&#xff0c; 打包了应用程序和应用程序所依赖的文件系统以及启动容器的配置文件&#xff0c;是启动容器的基础。镜像所打 包的文件内容就是容器的系统运行环…

C++初阶--String类的使用

string类 在C语言中&#xff0c;我们总是用char* 的类型来创建一个变量&#xff0c;存储一个字符串&#xff1b;当我们想对它进行修改或者读写时&#xff0c;需要自我创建空间和使用string.h的库函数来进行操作它&#xff1b; 而在C中&#xff0c;C专门提供了一个头文件 stri…

028 - STM32学习笔记 - ADC(二) 独立模式单通道中断采集

028 - STM32学习笔记 - 结构体学习&#xff08;二&#xff09; 上节对ADC基础知识进行了学习&#xff0c;这节在了解一下ADC相关的结构体。 一、ADC初始化结构体 在标准库函数中基本上对于外设都有一个初始化结构体xx_InitTypeDef&#xff08;其中xx为外设名&#xff0c;例如…

智能优化算法应用:基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于阴阳对算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阴阳对算法4.实验参数设定5.算法结果6.参考文献7.…

《2023全球隐私计算报告》正式发布!

2023全球隐私计算报告 1、2023全球隐私计算图谱2、国内外隐私计算相关政策3、隐私计算技术的最新发展4、隐私计算技术的合规挑战5、隐私计算的应用市场动态6、隐私计算开源整体趋势7、隐私计算的未来趋势 11月23日&#xff0c;由浙江省人民政府、商务部共同主办&#xff0c;杭州…