【C++模板】

news2024/11/17 5:50:40

目录

  • 一、什么是泛型编程
  • 二、函数模板
    • 2.1函数模板概念
    • 2.2函数模板格式
    • 2.3函数模板的原理
    • 2.4函数模板的实例化
  • 三、类模板
    • 3.1类模板的定义格式
    • 3.2类模板的成员函数的声明与定义分开的写法

一、什么是泛型编程

问题:如何实现一个加法函数呢?假设加法函数的参数类型有整形、浮点型、字符型等。
可能少年想的是利用函数重载来编写。如:

#include<iostream>
using namespace std;
int Add(int x, int y)
{
	return x + y;
}
float Add(float x, float y)
{
	return x + y;
}
double Add(double x, double y)
{
	return x + y;
}
char Add(char x, char y)
{
	return x + y;
}
int main()
{
	return 0;
}

虽然使用函数重载可以解决上面的需求,但是却有几点不足之处。如:
1.重载的函数仅仅是类型不同,代码复用率比较低,,只要有新类型出现时,就需要用户自己增加对应的函数。
2.代码的可维护性比较低,一个出错可能所以的重载均出错。
C++中为了解决这样的场景,特意存在一个类似模具的功能的工具名叫模板
而模板又分两类:
1.函数模板
2.类模板

二、函数模板

2.1函数模板概念

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

2.2函数模板格式

template<typename T1, typename T2,…,typename Tn>
返回值类型 函数名(参数列表){}
如:

#include<iostream>
using namespace std;
template<typename T>
T Add(T x, T y)
{
	return x + y;
}
int main()
{
	return 0;
}

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

2.3函数模板的原理

函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。
在这里插入图片描述
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此。

2.4函数模板的实例化

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

  1. 1.隐式实例化:让编译器自己推。但是有缺陷。如:
 #include<iostream>
using namespace std;
template<typename T>
bool IsGreater(const T& x, const T& y)
{
	return x > y;
}
int main()
{
	
	//该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
	// cout << IsGreater(3, 3.1415) << endl;
    //通过实参3将T推演为int,通过实参3.1415将T推演为double类型,但模板参数列表中只有一个T,
	//编译器无法确定此处到底该将T确定为int 或者 double类型而报错
	//注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
	
	// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
	cout << IsGreater(3, (int)3.1415) << endl;
	return 0;
}
  1. 显式实例化:在函数名后的<>中指定模板参数的实际类型
#include<iostream>
using namespace std;
template<typename T>
bool IsGreater(const T& x, const T& y)
{
	return x > y;
}
int main()
{
	
	//该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
	// cout << IsGreater(3, 3.1415) << endl;
    //通过实参3将T推演为int,通过实参3.1415将T推演为double类型,但模板参数列表中只有一个T,
	//编译器无法确定此处到底该将T确定为int 或者 double类型而报错
	//注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅
	
	// 此时有两种处理方式:
	//1. 用户自己来强制转化 
	//cout << IsGreater(3, (int)3.1415) << endl;

	//2. 使用显式实例化
	cout << IsGreater<int>(3, 3.1415) << endl;
	return 0;
}

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

三、类模板

3.1类模板的定义格式

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

如:

#include<iostream>
using namespace std;
template<class T>
class Vector
{
public:
	Vector(int capacity);
	{
		Capacity = capacity;
		Arr = new T[Capacity];
		Size = 0;
	}
	void Push_back(const T& val)
	{
		//CheckCapacity(*this);
		Arr[size++] = val;
	}
private:
	T* Arr;
	int Size;
	int Capacity;
};

int main()
{
	Vector<int> v1(4);//存储整形的顺序表
	Vector<char> v2(4);//存储字符的顺序表
	Vector<float> v3(4);//存储浮点型的顺序表
	return 0;
}

3.2类模板的成员函数的声明与定义分开的写法

当模板函数的声明与定义分开写法有点怪。比如:

#include<iostream>
using namespace std;
template<class T>
class Vector
{
public:
	Vector(int capacity);

	void Push_back(const T& val);
private:
	T* Arr;
	int Size;
	int Capacity;
};

template<class T>
Vector<T>::Vector(int capacity)
{
	Capacity = capacity;
	Arr = new T[Capacity];
	Size = 0;
}

template<class T>
void Vector<T>::Push_back(const T& val)
{
	//CheckCapacity(*this);
	Arr[size++] = val;
}

int main()
{
	Vector<int> v1(4);//存储整形的顺序表
	Vector<char> v2(4);//存储字符的顺序表
	Vector<float> v3(4);//存储浮点型的顺序表
	return 0;
}

此时Vector是类名,而Vector<int>、Vector<char>、Vector<float>才是类型。

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

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

相关文章

LeetCode94. 二叉树的中序遍历(递归与非递归)

写在前面&#xff1a; 题目链接&#xff1a;添加链接描述 编程语言&#xff1a;c 题目难度&#xff1a;简单 一、题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2] 示例 2&#xff1a;…

chatgpt赋能Python-python3_6怎么保存

Python3.6的保存方式简介 Python3.6是一种高级编程语言&#xff0c;由于其易读性和清晰性&#xff0c;成为了广泛使用的编程语言之一。Python3.6提供了丰富的特性和功能&#xff0c;使其成为了开发各种网站和Web应用程序的完美选择。在这篇文章中&#xff0c;我们将介绍Python…

8.2 综合案例2.0-远程遥控智能锁

综合案例2.0-远程遥控智能锁 案例说明1.硬件2.连线图3.dvr8833电机驱动使用说明 搭建云平台环境1.添加设备2.创建设备类型3.功能定义&#xff08;创建物模型&#xff09;4.ThingsX App 配置5.生成用户应用 App 代码1.更改MQTT信息2.测试 案例说明 生活中很多场景需要用到锁&am…

一、预约挂号微服务模块搭建

文章目录 一、预约挂号微服务模块搭建1、项目模块构建2、sql资源3、构建父工程&#xff08;yygh-parent&#xff09;3.1、添加配置pom.xml 4、搭建common父模块4.1、搭建common4.2、修改配置pom.xml 5、搭建common-util模块5.1、搭建common-util5.2、修改配置pom.xml5.3、添加公…

运筹优化求解迭代过程案例:图解法、单纯形法、单纯形表

运筹优化求解迭代过程案例:图解法、单纯形法、单纯形表 题目来自于清华大学出版的《运筹学》第四版。 一、问题描述 二、图解法 三、单纯形法 第一次迭代&#xff1a; 第二次迭代&#xff1a; 第三次迭代&#xff1a; 下面描述一下第三次迭代的详细过程&#xff1a; 从表达式…

【进阶】MySQL索引介绍

半个月没写mysql了&#xff0c;今天记录一下。。 了解到的索引有Btree&#xff0c;Hash表&#xff08;Memory存储引擎中&#xff09;&#xff0c;R-tree&#xff0c;Full-text等 MySql用的索引结构是Btree&#xff0c;B树所有节点都会出现在叶子节点中 目录 索引介绍&#…

容器目录挂载原理

前言 就我目前的对容器的了解, 使用namespace技术实现隔离, 使用cgroups技术实现资源限制. 但是具体是如何实现却从未深究过. 闲来无事, 挑其中的Mount Namespace来康康, 容器是如何实现目录隔离的. 目录隔离 在耗子叔的这篇文章中对此技术进行了介绍. 在c函数库中, 可通过…

Linux Audio (4) ASOC代码分析-基于kernel3.4.2

ASOC代码分析-基于kernel3.4.2 OverviewPlatformCPU DAICPU DMA CodecMechine Linux kernel版本&#xff1a;3.4.2 Overview linux ASoC音频设备驱动 ASoC是ALSA在SoC方面的发展和演变&#xff0c;它的本质仍然属于ALSA&#xff0c;但是在ALSA架构基础上对CPU相关的代码和Cod…

【python之django1.11框架一】django环境搭建及基本操作

1. 环境准备 开发环境&#xff1a;windows 11先安装好miniconda3。镜像地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/ 选择windows 64位下载。 下载地址&#xff1a; https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-lates…

JIRA的数据备份与恢复教程

目录 一、简介 二、数据备份&#xff08;默认系统会自动备份&#xff0c;不需要手动&#xff09; 1、使用管理员账号登录JIRA。 2、点击左上角的设置按钮&#xff0c;选择“系统”选项。 3、选择“备份系统”选项 4、开始手动备份 5、查看备份进度 三、数据恢复 1、使用…

MyBatisPlus入门案例

文章目录 1 入门案例步骤1:创建数据库及表步骤2:创建SpringBoot工程步骤3:勾选配置使用技术步骤4:pom.xml补全依赖步骤5:添加MP的相关配置信息步骤6:根据数据库表创建实体类步骤7:创建Dao接口步骤8:编写引导类步骤9:编写测试类 2 MybatisPlus简介 MyBatisPlus主要是对MyBatis的…

SQL注入 - Part 1

前置知识&#xff1a;sql前置的软件环境&#xff1a;预装了phpstudy_prodvwa&#xff0c;花了好长时间……时间主要浪费在听从chatgpt的建议装xampp上&#xff0c;卸载了mysql&#xff0c;重置了密码。其实使用xampp搭建环境也成功了&#xff0c;但是由于phpstudy教程比较多&am…

了解物理层下的传输媒体

1.了解物理层下的传输媒体 声明&#xff1a;该学习笔记来自湖科大教书匠&#xff0c;笔记仅做学习参考 笔记来源&#xff1a; 湖科大教书匠&#xff1a;物理层的基本概念 湖科大教书匠&#xff1a;物理层下面的传输媒体 1.1 物理层的基本概念 物理层考虑在连接各计算机的传输…

JQuery原理剖析——自己手写简易版JQuery

目录 为什么需要JQuery 在此之前回顾JavaScript对象知识&#xff1a; 自己手写的简易JQuery&#xff1a; 为什么需要JQuery 在我们之前写的JS代码中经常会遇见document.getElementById等等获取元素的对象&#xff0c;当大量的元素对象需要被获取时&#xff0c;就会有很多相似…

linux系统升级/更新OpenSSL版本操作流程记录

问题描述&#xff1a;有时 OpenSSL 版本过老升级&#xff0c;或者需要更新 OpenSSL 版本 1. 登录 linux 系统后输入 openssl version 查看现在使用的版本 我的输入后版本信息为&#xff1a;OpenSSL 1.1.1g FIPS 21 Apr 2020 &#xff0c;可以看到是一年前更新版本&#xff0c;…

openGauss数据库Package原理分析FAQ

FAQ的形式分析OpenGauss中package实现基础关键逻辑。 下面四个问题基本将市面上基于postgresql实现package的方法分成了几类。 例如问题一&#xff1a; openGauss使用包所在的namespace作为包函数的namespace。IvorySQL使用包本身的oid作为包函数的namespace。还有db创建一个…

微信小程序vue+nodejs校园快递物流取件及上门服务系统uniapp

系统分为用户和管理员两个角色 用户的主要功能有&#xff1a; 1.用户注册和登陆系统 2.用户查看系统的公告信息 3.用户在线快递下单&#xff0c;支付订单&#xff0c;在线订购快递取件 4.用户在线预约快递&#xff0c;填写快递预约信息 5.用户个人中心在线充值 6.用户个人中心修…

c++学习——概述、命名空间注意事项

C语言在c语言的基础上添加了面向对象编程和泛型编程的支持。 第一个helloworld #define _CRT_SECURE_NO_WARNINGS #include <iostream> using namespace std;//标准命名空间int main() {//cout是标准的输出流对象&#xff0c;打印字符串//endl是刷新缓冲区&#xff0c;…

软件详细设计总复习(一)【太原理工大学】

实验内容重点看&#xff0c;无需死记&#xff0c;它更是一种设计思想。要理解一种设计模式出现的意义是什么&#xff0c;它又是如何方便我们使用的&#xff1f;目的无非就是解耦、易扩充。题目问到优缺点&#xff0c;你只要知道该模式的设计思想就完全可以用自己的话概述&#…

chatgpt赋能Python-python3绘制图形

Python3绘制图形 – 让数据更加生动 作为一种可视化数据的工具&#xff0c;图形在数据分析和展示中扮演着重要的角色。Python3作为一种高效的编程语言&#xff0c;在图形方面也有自己的实现方式&#xff0c;让我们一起来了解Python3的图形绘制。 什么是Python3图形绘制&#…