【模板初阶】

news2024/11/19 19:43:02

目录

1. 泛型编程

 2. 函数模板

2.1 函数模板概念

2.2 函数模板格式

2.3 函数模板的原理

2.4 函数模板的实例化

 2.4.1 隐式实例化

2.4.2 显式实例化

2.5 模板参数的匹配原则

 3. 类模板

3.1 类模板的定义格式

3.2 类模板的实例化

4 总结


1. 泛型编程

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

void Swap(int& left, int& right)
{
 int temp = left;
 left = right;
 right = temp;
}
void Swap(double& left, double& right)
{
 double temp = left;
 left = right;
 right = temp;
}
void Swap(char& left, char& right)
{
 char temp = left;
 left = right;
 right = temp;
}
使用函数重载虽然可以实现,但是有一下几个不好的地方:
1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数 。
2. 代码的可维护性比较低,一个出错可能所有的重载均出错 。
那能否 告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码 呢?

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

 2. 函数模板

2.1 函数模板概念

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

 2.2 函数模板格式

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

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

就像我们实现的Swap函数,我们可以用函数模板来实现:

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

 当我们使用的时候,该模板会自动推导变量的类型,但是像下面这种写法就会报错:

 因为a和d的类型不同,与上面定义的模板矛盾了,处理方式可以这样:

Swap(a, (int&)d);
Swap((double&)a, d);

这种是采用了强转的方式,当然还可以采用修改模板用两个不同的参数。

template<typename T1,typename T2>

2.3 函数模板的原理

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

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

 

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

 2.4 函数模板的实例化

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

 2.4.1 隐式实例化

让编译器根据实参推演模板参数的实际类型.

template<class T>
T Add(const T& left, const T& right)
{
 return left + right;
}
int main()
{
 int a1 = 10, a2 = 20;
 double d1 = 10.0, d2 = 20.0;
 Add(a1, a2);
 Add(d1, d2);
}

这里就是靠编译器自动推演的参数类型。

2.4.2 显式实例化

在函数名后的<>中指定模板参数的实际类型.

int main()
{
 int a = 10;
 double b = 20.0;
 
 // 显式实例化
 Add<int>(a, b);
 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版本
}

像上面的程序,第一个会调用第一个Add,第二个才会调用通用模板。

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

 这个上面已经说了。

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

 3. 类模板

3.1 类模板的定义格式

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

 就拿我们之前用C语言实现的栈来说,如果我们要存储多种类型,那应该怎么办?

有人或许会说,那还不简单,不是有typedef吗?直接用typedef修改数据类型就好了吗?

但是这种方式我们多思考一下就知道行不通的,当我们想要两种数据同时存在不同的栈中那就没有办法处理了。那么如何正确的处理呢?

C语言的话难免不了要重新再创建一个栈,但是C++中我们可以用模板来处理这个问题。

template<class T>
class Stack
{
private:
	T* _a;
	int _top;
	int _capacity;
public:
	Stack(int capacity=4)
	{
		_a = nullptr;
		_sz = 0;
		_capacity = capacity;
	}
	~Stack()
	{
		//...
	}
	Stack(const Stack& st)
	{
		//...
	}
	push()
	{
		//...
	}
	pop()
	{
		//...
	}
	T top()
	{
		//...
	}
};

int main()
{
	Stack<int>st1(8);
	Stack<char>st2(16);
	return 0;
}

其中有些成员函数这里没有实现出来,相信大家可以自己实现出来,另外大家一定要注意用模板来实现类的时候定义和声明不要分离,否则就会报链接错误。

3.2 类模板的实例化

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

 就像我们上面使用的那样:

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

4 总结

本篇博客介绍了什么是泛型编程,再此基础上引出了模板的概念,介绍了函数模板和类模板的概念以及使用方法。如果·该文对你有帮助的话能不能一键3连支持一下博主呢?

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

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

相关文章

【Linux】简单理解静态库(.a)和动态库(.so)

在程序运行的基础原理这篇文章中&#xff0c;最后的代码进行链接过程&#xff0c;我们提到了动态库和静态库的概念。那么什么是动态库和静态库呢&#xff1f;我们来简单理解一下 静态库和动态库1.静态库1.1 静态链接优点1.2 静态链接缺点2.动态库2.1 动态链接的优点2.2 动态链接…

Ae 案例:制作漏光效果

本文介绍使用 Ae 内置效果插件制作漏光效果 Light Leak的一般方法与步骤。效果视频1、新建合成。持续时间&#xff1a;10 秒。2、新建纯色图层&#xff0c;命名为“漏光效果”&#xff0c;然后添加分形杂色 Fractal Noise效果。调整出如云朵一般柔和且层次多的分形杂色图。分形…

TCP中的状态转移(三种情况)

文章目录前言一、 TCP的生命周期二、另外两种挥手情况三、经典四问总结前言 博主个人社区&#xff1a;开发与算法学习社区 博主个人主页&#xff1a;Killing Vibe的博客 欢迎大家加入&#xff0c;一起交流学习~~ 在正常情况下&#xff0c;TCP要经过三次握手建立连接&#xff0c…

部署Web项目 (Linux)

部署Web项目 -- Linux一、Linux 环境搭建二、Linux 常用命令三、搭建 Java 部署环境3.1 JDK3.2 Tomcat3.3 MySQL四、部署 Web 项目4.1 什么是部署4.2 数据库建表4.3 构建项目并打包4.4 拷贝到 Tomcat 中4.5 验证一、Linux 环境搭建 这里我们使用的方法是购买云服务器 (CentOS …

组合数素数判定++和* *t=*afor循环你真的门儿清吗救济金发放

目录 P63_习题4-1_组合数 为什么m n-m P64_习题4-3_素数判定 为什么要floor 到底为什么判断到sqrt(n)即可 和* *t*a for循环你真的门儿清吗 为什么要把较大的数组放在main函数外 P82_eg4-3_救济金发放_UVa133 P63_习题4-1_组合数 防止溢出&#xff0c;又因为m < n…

【JavaScript】module let Object.setPrototypeOf()以及箭头函数

案例&#xff1a;选项卡 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthde…

python 3 添加环境变量后 仍然无法用cmd输入python访问,而是弹出应用商店 | 两种解决方法

问题描述 今天重装python3.10后发现即使正确添加环境变量时&#xff0c;仍然无法用cmd输入python或python3访问&#xff0c;而是弹出应用商店。但是如果输入cmd里输入py是可以运行的&#xff08;证明python是正常安装好的&#xff09;。 这里给出两种解决方法&#xff0c;一种…

指针进阶(详解)

指针进阶一.字符指针二.指针数组1.一次打印多个字符串2.模拟二维数组三.数组指针1.定义2.应用四.函数指针五.函数指针数组六.指向函数指针数组的指针七.回调函数在开始这篇之前&#xff0c;前面有两篇指针初阶&#xff0c;如果需要的话可以去看看哟&#xff01;指针初阶1&#…

网络安全等级保护确定定级对象

声明 本文是学习github5.com 网站的报告而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 网络安全等级保护确定定级对象 信息系统 定级对象的基本特征 作为定级对象的信息系统应具有如下基本特征&#xff1a; 具有确定的主要安全责任主体&#xff1…

【MySQL进阶教程】SQL优化

前言 本文为 【MySQL进阶教程】SQL优化 相关知识&#xff0c;下边将对主键优化&#xff0c;order by优化&#xff0c;group by优化&#xff0c;limit优化&#xff0c;count优化&#xff0c;update优化等进行详尽介绍~ &#x1f4cc;博主主页&#xff1a;小新要变强 的主页 &am…

利用Python为女神制作一个专属网站

快跟随小编一起学习一下如何利用Python语言制作一个专属的网站送给女神吧&#xff01; 如觉得博主文章写的不错或对你有所帮助的话&#xff0c;还望大家多多支持呀&#xff01;关注、点赞、收藏、评论。 目录如觉得博主文章写的不错或对你有所帮助的话&#xff0c;还望大家多多…

1995-2019年全球清廉指数

1995-2019年全球清廉指数 1、时间&#xff1a;1995-2019年 2、来源&#xff1a;透明国际&#xff08;Transparency International&#xff09; 3、区域&#xff1a;全球170多个国家 4、指标说明&#xff1a; 清廉指数&#xff08;Corruption Perceptions Index&#xff0c…

【自学C++】C++ short

C short C short教程 C 中的 short 用来表示一个 整数&#xff0c;也可以叫做短整型&#xff0c;如果我们需要表示的整数比较小&#xff0c;那么我们可以使用 short 来定义&#xff0c;这样可以节省系统资源。 C short定义详解 语法 short int varname value; short varn…

【django】关联模型类中数据的增删改查操作总结

文章目录一、多对一正向操作1、改方法一方法二2、删3、查反向操作案例1&#xff1a;查询百度渠道下的所有学生信息案例2&#xff1a;新增一个百度渠道下的学生1、增直接创建Student对象2、改方法一&#xff1a;add()案例1&#xff1a;将s1,s2,s3添加到百度渠道中方法二:替换对象…

【Java】遨游在多线程的知识体系中(二)

前言&#xff1a;一、分析上篇多线程不安全原因1. count 操作是三个步骤&#xff0c;load add save2. 多个线程之间的调度是无序的&#xff0c;两个线程的上述三个操作可能存在多种不同的相对顺序3. 线程针对变量的修改不是原子的4. 内存可见性5.指令重排序二、synchronize 关键…

Java中clone的浅拷贝和深拷贝区别以及方法详解

克隆定义 在 Java 中&#xff0c;克隆是创建原始对象的精确副本的过程。它本质上意味着能够创建一个与原始对象具有相似状态的对象。 复制对象&#xff0c;首先要分配一个和源对象同样大小的空间&#xff0c;在这个空间中创建一个新的对象。 new对象和clone区别 使用new操作符创…

Python批量采集无水印短视频内容

前言 短视频流行起来可不是一年两年了&#xff0c;现在很多年轻人都在玩短视频&#xff0c;有些的单纯就是看看&#xff0c;而有些的就是自己发视频 我每天刷视频&#xff0c;一刷就停不下来&#xff0c;应该还是有蛮多人跟我一样的吧 那有没有想法用自己所学的python知识&a…

Linux管道——进程间通信(匿名管道、命名管道)

文章目录一、进程间通信1.1 进程间通信的概念1.2 进程间通信的目的1.3 进程间通信的本质1.4 进程间通信的分类二、管道2.1 匿名管道① 匿名管道的使用场景② 匿名管道实现通信的原理③ 创建匿名管道 pipe函数④ fork共享管道⑤ 匿名管道的五个特点⑥ 匿名管道的四种特殊情况2.2…

开发模型和测试模型,考点归纳,你都记住了吗?

目录 前言 一、开发模型 1.1、瀑布模型 1.2、螺旋模型 1.3、迭代模型和增量模型 1.4、敏捷模型 敏捷开发最流行的方式——scrum模型 二、测试模型 2.1、V模型 2.2、W模型&#xff08;双V模型&#xff09; 前言 对于模型&#xff0c;需要重点掌握特点&#xff0c;缺点&…

模板编程:constexpr +特例化 判断质数

重点&#xff1a; 1.constexpr 函数支持在编译期间完成计算 2.特例化是模板中一种定义 using namespace std;//编译期进行判断 constexpr bool isPrime(unsigned int p) {for (unsigned int d2;d<p/2;d){if (p % d 0){return false;}}return p > 1; }template<int…