C++模板使用

文章目录

目录

文章目录

前言

一、交换函数(泛型编程)

二、函数模板

        2.1 函数模板概念

        2.2函数模板格式

        2.3使用方法

2.4 函数模板的原理

2.4.1库中的swap

2.5 函数模板的实例化

2.6 模板参数的匹配原则

三、类模板

        3.1 类模板的定义格式

3.2类模板声明和定义分离


前言

        C语言阶段要实现不同类型的交换函数swap,需要重复写很多代码,需要造很多的轮子。为了提高程序员写代码的效率,C++出现了泛型编程的概念,模板应运而生。


一、交换函数(泛型编程)

        如何实现一个通用的交换函数呢?

void Swap(int& left, int& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(double& left, double& right)
{
	int temp = left;
	left = right;
	right = temp;
}

void Swap(char& left, char& right)
{
	int temp = left;
	left = right;
	right = temp;
}
//.......

        要进行不同类型的交换需要写多个函数。

使用函数重载虽然可以实现,但是有一下几个不好的地方:
1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那能否告诉编译器一个模板,让编译器根据不同的类型利用该模板来生成代码呢
 

如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多头发。巧的是前人早已将树栽好,我们只需在此乘凉。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

二、函数模板

        2.1 函数模板概念

        函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

        2.2函数模板格式

template<typename T1, typename T2,......,typename Tn>
返回值类型 函数名(参数列表){}
template<typename T>
void Swap( T& left, T& right)
{
    T temp = left;
    left = right;
    right = temp;
}

注意:typename是用来定义模板参数关键字也可以使用class(切记:不能使用struct代替class)

        2.3使用方法

       下面的Swap使用的是否为同一个?

#include <iostream>
using namespace std;

template<typename T>
void Swap(T& left, T& right)
{
	T temp = left;
	left = right;
	right = temp;
}
int main()
{
	int a = 1, b = 0;
	Swap(a, b);
	double c = 1.1, d = 2.2;
	Swap(c, d);
	int* p1 = &a, * p2 = &b;
	Swap(p1, p2);
	return 0;
}

不要被调试欺骗了,实际上它们调用的不是同一个函数,而是不同的三个函数。这是编译器自动生成的。类型不一样,开辟的大小也不一样,这是编译器造成的假象。

通过汇编观察:

调用的函数地址不相同,所以不是一个函数。

那么模板的原理是什么?

2.4 函数模板的原理

        函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

这个叫做函数模板的实例化。生成一个函数。

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

        实际过程没有变,只是编译器帮助我们去写。

2.4.1库中的swap

        在C语言阶段我们要交换函数swap需要自己写,而在C++阶段,由于swap使用的频繁,使用C++直接将swap纳入库中,库中的swap就是模板写的:

以后C++中调用库的std就可以了。

2.5 函数模板的实例化

        用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化

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

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double b1 = 10.2, b2 = 20.2;
	Add(a1, a2);
	Add(b1, b2);
    /*
    该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
    通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
    编译器无法确定此处到底该将T确定为int 或者 double类型而报错
    注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
	Add(a1, b1);
    */
	return 0;
}

像Add(a1,b1);这样编译器不知道该怎么推演。此处有种处理方式:1.用户自己来强制转化 2.使用显示实例化

Add(a1, (int)b1);

也可以像下面这样:
        下面这样就不会有问题,使用auto接收返回值的类型。

template<class T1,class T2>
auto Add(const T1& left, const T2& right)
{
	return left + right;
}
int main()
{
	int a1 = 10, a2 = 20;
	double b1 = 10.2, b2 = 20.2;
	Add(a1, a2);
	Add(b1, b2);
	Add(a1, b1);
	return 0;
}

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

        如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。

int main(void)
{
    int a = 10;
    double b = 20.0;
    // 显式实例化
    Add<int>(a, b);
    return 0;
}

有一种情况必须进行显示实例化:

template<class T>
T* func(int a)
{
    //返回一个T的空间
    T* p = (T*)operator new(sizeof(T));
    return p;
}

int main()
{
    //只能进行显示实例化
    int* ret = func<int>(1);
    return 0;
}

2.6 模板参数的匹配原则

        1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

// 专门处理int的加法函数
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>
auto Add(const T1& left, const T2& right)
{
	return left + right;
}
void Test()
{
	Add(1, 2); // 与非模板函数匹配,编译器不需要特化
	Add<int>(1, 2); // 调用编译器特化的Add(T)版本
	Add(2, 3.1); //调用模板Add(T1,T2)版本
	Add<double, int>(3.1, 2);//调用编译器特化的Add(T1,T2)版本
}

结果:

2. 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板

// 专门处理int的加法函数
int Add(int left, int right)
{
    return left + right;
}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
    return left + right;
}
void Test()
{
    Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
    Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数 
}

3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

匹配:

1.都有的情况,优先匹配普通函数+参数匹配(成品+口味对)。

2.没有普通函数,优先匹配参数匹配+函数模版(成品+口味对)。

3.只有一个,类型转换一下也能用,也可以匹配调用(口味不对,将就一下也行)。

三、类模板

        3.1 类模板的定义格式

template<class T1, class T2, ..., class Tn>
class 类模板名
{
    // 类内成员定义
};

        模板在C++中更多应用类模板。

如果不用模板,我们想要使用俩个不一样的栈stack存储俩个不同类型的数据时,使用typedef对类型进行更名,只能对一个类型使用。

typedef int T;
class Stack
{
public:
	Stack(size_t capacity = 4)
	{
		_array = (T*)malloc(sizeof(T) * capacity);
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}

	void Push(const T& data)
	{
		//扩容
		_array[_size] = data;
		++_size;
	}
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};

int main()
{
	Stack st1;//int
	Stack st2;//double
	return 0;
}

C语言做不到,要做到只能写俩个类。所以使用模板节省了很多代码量。

// 类模版
template<class T>
class Stack
{
// 代码....
}

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类

	Stack<int> st1;//int
	Stack<double> st2;//double

模板是写给编译器的。这俩个栈的类型不一样。是俩个不同的类实例化的对象

3.2类模板声明和定义分离

          模板的声明和定义分离最好不要分文件到.h 和 .cpp。因为会出很多链接错误

// 类模版
template<class T>
class Stack
{
public:
	//。。。。
	void Push(const T& data);
private:
	T* _array;
	size_t _capacity;
	size_t _size;
};
//在同一个文件中
template<class T>
void Stack<T>::Push(const T& date)
{
	//扩容
	_array[_size];
	++_size;
}

全部放在类中,也不用担心内联问题,因为内联只是给编辑器的建议,要经过编辑器的允许才能是内联。


如果你又所收获可以留下你的关注和点赞,谢谢你的观看!!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot事务控制中A方法调用B方法@Transactional生效与不生效情况实战总结

介绍 本篇对Springboot事务控制中A方法调用B方法Transactional生效与不生效情况进行实战总结&#xff0c;让容易忘记或者困扰初学者甚至老鸟的开发者&#xff0c;只需要看这一篇文章即可立马找到解决方案&#xff0c;这就是干货的价值。喜欢的朋友别忘记来个一键三连哈&#x…

抖音本地生活服务商入驻指南分享!

当前&#xff0c;各大平台的团购外卖业务持续火爆&#xff0c;并逐渐成为众多创业赛道中的大热门。其中&#xff0c;本地生活服务更是在短时间内杀出重围&#xff0c;成为创业者们的首选。 根据抖音生活服务近日发布的《2023年度数据报告》&#xff0c;2023年&#xff0c;抖音生…

微信小程序图片懒加载如何实现?

微信小程序开发时&#xff0c;对于有图片的列表在加载时&#xff0c;为了用户体验更好&#xff0c;必需要对图片做懒加载。 如下图所示&#xff0c;页面在打开时&#xff0c;图片会按需加载&#xff0c;这样用户体验没有那么生硬。 以下将介绍图片懒加载的步骤&#xff1a; 1.…

R18 NTN中的RACH-less HO

在看R18 38.300时,发现NTN场景 增加了如下黄色字体的内容,R18 NTN支持了RACH-less HO,索性就简单看了看。 NTN RACH less HO相关的描述主要在38.331,38.213和38.321中。38.300中的描述显示:网络侧会通过RRCReconfiguration消息将RACH-less HO相关的配置下发给UE, 其中会包…

Java语言ADR药物不良反应系统源码Java+IntelliJ+IDEA+MySQL一款先进的药物警戒系统

Java语言ADR药物不良反应系统源码JavaIntelliJIDEAMySQL一款先进的药物警戒系统源码 ADR药物不良反应监测系统是一个综合性的监测平台&#xff0c;旨在收集、报告、分析和评价药品在使用过程中可能出现的不良反应&#xff0c;以确保药品的安全性和有效性。 以下是对该系统的详细…

Java 面向对象编程(OOP)

面向对象编程&#xff08;Object-Oriented Programming&#xff0c;OOP&#xff09;是Java编程语言的核心思想之一。通过OOP&#xff0c;Java提供了一种结构化的编程方式&#xff0c;使代码更易于维护和扩展。 一、类和对象 1. 类的定义 类是对象的蓝图或模板&#xff0c;定…

【qt】一次性学会所有对话框

对话框 一.前言二.文件对话框1.选择一个文件2.选择多个文件3.选择目录4.保存文件 三.颜色对话框1.获取颜色 四.字体对话框1.获取字体 五.输入对话框1.输入文本2.输入整数3.输入小数4.输入条目 六.消息对话框1.问题框2.信息框3.警告框4.危机框5.关于框6.关于qt框七.总结 一.前言…

CSS学习笔记:动画——使用animation添加动画效果

过渡和动画 啥是过渡? 例如transition: all 0.5s; -> 拥有该属性的标签&#xff0c;在样式改变时&#xff0c;将在设定的时间内逐渐过渡到另一个样式 啥是动画&#xff1f; 和过渡有点类似&#xff0c;只不过常常用于实现多个状态间的变化过程&#xff0c;动画过程可控…

基于PHP+MySQL组合开发的720VR全景小程序源码系统 一键生成三维实景 前后端分离带网站的安装代码包以及搭建教程

系统概述 这款源码系统是专门为实现 720VR 全景展示而设计的。它结合了先进的技术和创新的理念&#xff0c;能够将真实场景以全景的形式呈现给用户&#xff0c;让用户仿佛身临其境。该系统采用 PHP 进行后端开发&#xff0c;MySQL 作为数据库管理系统&#xff0c;确保了系统的…

【JAVA |Object类重写实例】Cloneable 接口、Comparable接口、比较器

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; &#x1f388;丠丠64-CSDN博客&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起…

阿贝云免费虚拟主机及免费云服务器评测

阿贝云是一家提供免费虚拟主机和免费云服务器的公司&#xff0c;其服务质量备受用户好评。用户可以通过阿贝云的网站 https://www.abeiyun.com 进行申请并获得免费服务。首先&#xff0c;我们来看看阿贝云的免费虚拟主机服务。免费虚拟主机提供了足够的存储空间和带宽&#xff…

HackTheBox-Machines--Cronos

文章目录 0x01 信息收集0x02 命令注入漏洞0x03 权限提升 Cronos 测试过程 0x01 信息收集 1.端口扫描 发现 SSH&#xff08;22&#xff09;、DNS&#xff08;53&#xff09;、HTTP&#xff08;80&#xff09;端口 nmap -sC -sV 10.129.227.2112.53端口开启&#xff0c;进行DNS…

靶机Moonraker_1练习报告

Moonraker: 1靶机练习实践报告 一、安装靶机 靶机是.ova文件&#xff0c;需要用VirtualBox打开&#xff0c;但我习惯于使用VMWare,因此修改靶机文件&#xff0c;使其适用于VMWare打开。 解压ova文件&#xff0c;得到.ovf文件和.vmdk文件。 直接用VMWare打开.ovf文件即可。 …

【VTKExamples::Utilities】第四期 CameraModifiedEvent

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例CameraModifiedEvent,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~YO 1. CameraModifi…

OpenMV的VisionBoard视觉识别开发板学习记录

此篇博客仅用于对VisionBoard的开发板的学习研究记录&#xff0c;没有教学内容。 一、资料来源 开发板资料链接 开发板环境搭建手册 开发板视频教程 板子的资料网站 openmv官方的网站 目录 一、资料来源二、针对 VisionBoard的目标识别和定位总结1. 目标识别功能1.1 物体检测…

react ant 表格实现 拖拽排序和多选

项目背景 : react ant 要实现 : 有多选功能(实现批量删除 , 也可以全选) 可以拖拽(可以复制 , 方便顶部的搜索功能) 要实现效果如下 1 这是最初的拖拽功能实现 , 不能复制表格里的内容 , 不符合要求 2 更改了ROW的内容 , 实现了可以复制表格内容 代码 //控制是否可以选中表格…

Oracle数据库操作问题汇总

一、简介 Oracle Database&#xff0c;又名Oracle RDBMS&#xff0c;或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是世界上流行的关系数据库管理系统&#xff0c;系统可移植性好、使用方便、功能强&…

数据结构--二叉树--顺序存储判断是否二叉搜索树(2022统考真题)

数据结构–二叉树–顺序存储判断是否二叉搜索树(2022统考真题) 题目描述&#xff1a; 思路 二叉搜索树&#xff08;Binary Search Tree&#xff0c;简称BST&#xff09;是一种具有以下性质的二叉树&#xff1a; 对于树中的每个节点 N&#xff0c;它的左子树&#xff08;如果…

重学java 49 List接口

但逢良辰&#xff0c;顺颂时宜 —— 24.5.28 一、List接口 1.概述: 是collection接口的子接口 2.常见的实现类: ArrayList LinkedList Vector 二、List集合下的实现类 1.ArrayList集合的使用及源码分析 1.概述 ArrayList是List接口的实现类 2.特点 a.元素有序 —> 按照什么顺…

Oracle中rman的增量备份使用分享

继上次使用RMAN的全量备份和异机还原以后&#xff0c;开始研究一下增量备份和还原的方法。相比于全量RMAN的备份还原&#xff0c;增量的备份还原就相对简单。本实践教程直接上操作&#xff0c;还是回归到一个问题&#xff0c;就是关于两个数据库创建时候&#xff0c;必须保持or…