C++:模板初阶

news2024/11/18 3:34:34

本篇文章主要对模板有个简单的认识,方便我们后面对模板进行更加深入的学习。

目录

1.泛型编程

2.函数模板

2.1 函数模板的概念

2.2 函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

2.5 模板参数的匹配原则

3.类模板

3.1 类模板的格式定义

3.2 类模板的实例化


1.泛型编程

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

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

void Swap(char& left, char& right)
{
	char t = left;
	left = right;
	right = t;
}

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

//.....

使用函数重载虽然可以实现,但是有一下几个不好的地方:

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

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

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

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

模板分为函数模板类模板,我们下面来具体介绍一下。

2.函数模板

2.1 函数模板的概念

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

2.2 函数模板格式

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

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

//template<class T> //这里class 与 typename 都可以,目前没有什么区别
//template<typename T>
//template<typename T1, typename T2>
template<class T>
void Swap(T& left, T& right)
{
	T t = left;
	left = right;
	right = t;
}

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

2.3 函数模板的原理

那么如何解决上面的问题呢?大家都知道,瓦特改良蒸汽机,人类开始了工业革命,解放了生产力。机器生产淘汰掉了很多手工产品。本质是什么,重复的工作交给了机器去完成。有人给出了论调:“懒”人创造世界

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

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

2.4 函数模板的实例化

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

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

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


int main()
{
	int i = 1, j = 2;
	Swap(i, j);
	cout << i << " " << j << endl;

	double a = 1.1, b = 2.2;
	Swap(a, b);
	cout << a << " " << b << endl;

    //该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
    //通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,
    //编译器无法确定此处到底该将T确定为int 或者 double类型而报错
    //注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
    //Add(i, a);
    
    // 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化    

    Add(i, (int)a);//强制类型转换
    Add((double)i, a);//强制类型转换
    
	return 0;
 }

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

int main(void)
{
    int a = 10;
    double b = 20.0;

    // 显式实例化
    Add<int>(a, b);//确定T的类型是int
    return 0;
}

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

2.5 模板参数的匹配原则

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

// 专门处理int的加法函数
int Add(int left, int right)
{
    return left + right;
}

// 通用加法函数
template<class T>
T Add(T left, T right)
{
    return left + right;
}

void Test()
{
    Add(1, 2); // 与非模板函数匹配,编译器不需要特化,会优先配备最适合的
    Add<int>(1, 2); // 显式调用,调用编译器特化的Add版本
}

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. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

3.类模板

3.1 类模板的格式定义

template<class T1, class T2, ..., class Tn>
class 类模板名
{
    // 类内成员定义
};
//栈
template<class T>
class Stack
{
public:
	Stack(int capacity = 4)
		:_a(nullptr)
		, _size(0)
		, _capacity(capacity)
	{
		cout << "Stack()" << endl;
		_a = new T[capacity];
	}

	void Push(const T& a)
	{
		//CheckCapacity();
		_a[_size++] = a;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		delete[] _a;
		_size = 0;
		_capacity = 0;
	}
//类名 Stack
//类型 Stack<T>
//在我们之前没有学习模板时,类名和类型是相同的,都是Stack

private:
	T* _a;
	int _size;
	int _capacity;
};

3.2 类模板的实例化

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

// Vector类名,Vector<int>才是类型
Stack<int> s1;
Stack<double> s2;

本篇结束!

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

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

相关文章

2023年【北京市安全员-C3证】最新解析及北京市安全员-C3证作业考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 北京市安全员-C3证最新解析是安全生产模拟考试一点通总题库中生成的一套北京市安全员-C3证作业考试题库&#xff0c;安全生产模拟考试一点通上北京市安全员-C3证作业手机同步练习。2023年【北京市安全员-C3证】最新解…

缺失找不到msvcr71.dll无法执行代码,应用程序无法启动的解决方法

最近我在使用电脑时遇到了一个问题&#xff0c;提示我缺少 msvcr71.dll 这个文件。这个文件是系统中的一个动态链接库文件&#xff0c;常用于支持一些运行在 Windows 系统上的程序。 当我发现这个问题时&#xff0c;我感到有点困惑和焦虑。因为我需要使用的软件要求系统中必须…

SimpleCG图像操作基础

上一篇我们介绍了程序的交互功能&#xff0c;就可以编写一些简单的游戏了&#xff0c;例如贪吃蛇、扫雷、俄罗斯方块、五子棋等&#xff0c;都可以使用图形函数直接绘制&#xff0c;在后续文章中将逐一展示。不过编写画面丰富游戏离不开图像&#xff0c;所以本篇我们介绍一下基…

零信任身份管理平台,构建下一代网络安全体系

随着数字化时代的到来&#xff0c;网络安全已成为企业和组织面临的一项重要挑战。传统的网络安全方法已经无法满足不断演变的威胁和技术环境。近期&#xff0c;中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;发布了《零信任发展研究报告&#xff08; 2023 年&a…

全球领先的即时通讯厂家,为企业提供卓越沟通解决方案

不同部门的协同合作是企业内部高效运作的关键&#xff0c;然而&#xff0c;传统的沟通方式往往会受到时间、空间以及信息传递效率的限制&#xff0c;给企业带来不必要的困扰。随着科技的不断进步&#xff0c;解决这一问题的新利器应运而生——WorkPlus&#xff0c;一款基于即时…

链表增删操作问题及解决方法

目录 链表增加元素首部中间尾部 链表删除元素首部中间尾部 链表是一种常用的数据结构&#xff0c;用于存储和组织数据。在链表中&#xff0c;增加和删除元素是常见的操作。然而&#xff0c;在进行链表的增删操作时&#xff0c;对于首部、中间和尾部位置的元素&#xff0c;都存在…

UWB安全数据通讯STS-加密、身份认证

DW3000系列才能支持UWB安全数据通讯&#xff0c;DW1000不支持 IEEE 802.15.4a没有数据通讯安全保护机制&#xff0c;IEEE 802.15.4z中指定的扩展得到增强&#xff08;在PHY/RF级别&#xff09;&#xff1a;增添了一个重要特性“扰频时间戳序列&#xff08;STS&#xff09;”&a…

mysql修改root用户的密码

mysql修改root用户的密码 方法1&#xff1a; 用SET PASSWORD命令方法2&#xff1a;用mysqladmin方法3&#xff1a;用UPDATE直接编辑user表方法4&#xff1a;在忘记root密码的时候&#xff0c;可以这样以windows为例&#xff1a; 连接mysql问题 mysql备份工具之mysqldump 方法1&…

反转链表(java)

大家好我是苏麟今天说一说链表常见的简单题目 . BM1 反转链表 牛客BM1 反转链表 : 描述 : 给定一个单链表的头结点(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 分析 : …

AP5101C 高压线性恒流 LED电源驱动IC 3D打印机显示灯驱动器

1&#xff0c;产品描述 AP5101C 是一款高压线性 LED 恒流芯片 &#xff0c; 简单 、 内置功率管 &#xff0c; 适用于6- 100V 输入的高精度降压 LED 恒流驱动芯片。电流2.0A。AP5101C 可实现内置MOS 做 2.0A,外置 MOS 可做 3.0A 的。AP5101C 内置温度保护功能 &#xff0c;温度…

3. 实战入门

3. 实战入门 文章目录 3. 实战入门3.1 Namespace3.1.1测试两个不同的名称空间之间的 Pod 是否连通性 3.2 Pod3.3 Label3.4 Deployment3.5 Service 本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 3.1 Namespace Namespace是kubernet…

IDEA使用内置database数据库连接mysql报错:javax.net.ssl.SSLHandshakeException

参考一些博客的方式&#xff1a; 使用idea内置database连接数据库报错javax.net.ssl.SSLHandshakeException: No appropriate protocol_idea database ssl_你当像山的博客-CSDN博客 他们的方式是&#xff1a;在url后添加useSSLfalse 介绍另外一种方式&#xff1a; 点击datab…

大规模语言LLaVA:多模态GPT-4智能助手,融合语言与视觉,满足用户复杂需求

大规模语言LLaVA&#xff1a;多模态GPT-4智能助手&#xff0c;融合语言与视觉&#xff0c;满足用户复杂需求 一个面向多模式GPT-4级别能力构建的助手。它结合了自然语言处理和计算机视觉&#xff0c;为用户提供了强大的多模式交互和理解。LLaVA旨在更深入地理解和处理语言和视…

小程序setData动态传递key

有些时候可能需要根据key是个变量 比如 let keyName "name" this.setData({keyName :"张三" })本来想将keyName替换为name的&#xff0c;但是小程序只会在data中定义一个key为keyName ,value为“张三”的一条数据。 正确写法为&#xff1a; let keyNam…

SS626V100_SDK_V2.0.1.0 安装编译 osdrv 问题汇总

目录 前言1、开发环境2、在 linux 服务器上安装交叉工具链2.1 安装 aarch64-mix410-linux.tgz2.2 安装 cc-riscv32-cfg11-musl-20220523-elf.tar.gz2.3 检查工具链版本&#xff0c;打印版本则表示配置成功 3、安装 SDK3.1 SS626V100_SDK_V2.0.1.0 安装包位置3.2 解压缩并展开 S…

怎么把图片改成jpg格式?

怎么把图片改成jpg格式&#xff1f;大家都知道&#xff0c;随着计算机被发明到现在已经存在了很多年&#xff0c;在这么多的的技术发展过程中&#xff0c;也形成了种类非常多的图片文件格式&#xff0c;例如平时我们能接触到的图片格式有jpg、png、gif、bmp、heic、tiff、jfif、…

力扣-python-两数之和

题解&#xff1a; class Solution(object):def twoSum(self, nums, target):# 遍历列表for i in range(len(nums)):# 计算需要找到的下一个目标数字res target-nums[i]# 遍历剩下的元素&#xff0c;查找是否存在该数字if res in nums[i1:]:# 若存在&#xff0c;返回答案。这里…

云安全—云计算架构

0x00 前言 云中的所有的软件都是作为服务来提供的&#xff0c;需要支持多租户&#xff0c;需要提供伸缩的能力&#xff0c;所有需要特定的软件架构来进行支持。 0x01 云计算的本质 1.云计算系统工程 主要特点是&#xff1a; 弹性透明模块化通用动态多租赁 云计算通过对硬…

基于JavaWeb+SpringBoot+Vue健身俱乐部系统的设计和实现

基于JavaWebSpringBootVue健身俱乐部系统的设计和实现 源码传送入口前言主要技术系统设计功能截图Lun文目录订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 源码传送入口 前言 1.1 课题背景 随着互联网的发展&#xff0c;电脑已成为人们生活中必不可少的生活办公工…