C++——模板初阶

泛型编程

C语言中交换两个变量数据的内容一般是这样实现的

#include<iostream>using namespace std;void swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}
int main()
{int x = 5;int y = 7;swap(&x,&y);cout << "x=" << x << " ";cout << "y=" << y << " ";}

但自从学了C++引用以后 就不用再传地址和用指针接受实参地址了,直接使用引用 既高效又不开辟栈帧空间。

#include<iostream>using namespace std;void swap(int &xx, int&yy)
{int tmp = xx;xx = yy;yy = tmp;
}
int main()
{int x = 5;int y = 7;swap(x,y);cout << "x=" << x << " ";cout << "y=" << y << " ";}

结果是一样的。 

但如果要实现多种不同类型数据之间的交换呢?

C++可以使用函数重载

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++的祖师爷已经考虑到了这点,并且已经实现了出来。
正所谓前人栽树 后人乘凉 
一般是 泛型编程
泛型编程编写与类型无关的通用代码,是代码复用的一种手段,模板是泛型编程的基础。

模板

模板分为 函数模板类模板

函数模板

函数模板是怎么实现两个数据之间的交换呢?
#include<iostream>using namespace std;template<class T>
void swap(const T&x, const T&y)
{T tmp = x;x = y;y = x;
}
int main()
{int x = 5;int y = 7;swap(x,y);cout << "x=" << x << " ";cout << "y=" << y << " ";}

函数模板的格式

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

返回值类型 函数名(参数)

typename是用来定义模板参数的关键字,也可以用class。(一般是用class,但不能以struct替代class)

#include<iostream>using namespace std;template<class T>
void swap(const T&x, const T&y)
{T tmp = x;x = y;y = x;
}
int main()
{int x = 5;int y = 7;double a = 1.34;double b = 2.34;swap(x,y);swap(a, b);cout << "x=" << x << endl;cout << "y=" << y << endl;cout << "a=" << a << endl;cout << "b=" << b << endl;}

模板会根据你传的实参类型自动推演生成对应数据类型的函数。 

但它们俩调用的却不是同一个函数 通过反汇编就可以看出来

编译器自动完成的事情。

函数模板的原理

要清楚模板是在编译阶段就调用完成的。

当数据类型使用函数模板时,编译器通过对实参类型的推演,将T确定为与之对应的类型,然后专门生成处理该数据类型的代码。
当然模板里面的定义的关键字类型也可以 有多种类型
#include<iostream>using namespace std;template<class T,class Y>
T add(const T& x, const Y& y)
{return x + y;
}int main()
{int a = 4;double b = 3.14;int ret=add(a, b);cout << ret << endl;
}

函数模板的实例化

模板参数语法其实很类似函数参数,函数参数定义的形参对象,模板参数定义的是类型 

用不同类型的参数使用函数模板时,是函数模板的实例化。

而实例化又分为隐式实例化显示实例化

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

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

#include<iostream>using namespace std;template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int main()
{int a = 5;int b = 11;double c = 3.14;double d = 4.14;int ret = Add(a, b);double ret1 = Add(c, d);int ret2 =Add(a, d);error该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int 或者 double类型而报错注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅所以为了解决这个问题 1.要么用户自己强转 2.要么显式实例化int ret3 = Add(a, (int)d);cout << ret << endl;cout << ret1 << endl;cout << ret3 << endl;显式实例化cout << Add<int>(a, c) << endl;cout << Add<double>(a, b) << endl;
}

 一般这种时候就要显式实例化

否则编译器也不知道f是返回值是什么?

 模板参数的匹配原则

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

#include<iostream>using namespace std;普通函数
int Add(const int x, const int y)
{cout << "(const int x, const int y)" << endl;return x + y;
}函数模板
template<class T>
T Add(const T& x, const T& y)
{cout << "(const T& x, const T& y)" << endl;return x + y;
}int main()
{Add(1, 2);Add(1.1,1.2);
}

当我把函数模板屏蔽后再运行

double到int可以进行隐式类型转换 所以去调用了普通函数。

由此我们可以发现模板参数匹配调用原则:

1.有现成的吃现成的   (第一个int类型去调用普通函数 第二个double类型去调用函数模板)

2.有适合的吃适合的,哪怕自己要现做 

3.没有就将就吃 (函数模板屏蔽后,去调用普通函数)

类模板

类模板的格式

template<class T1,class T2class Tn>

class 类模板名

{
// 类内成员定义

}

#include<iostream>using namespace std;template<class T>class stack
{
public:nstack(int n = 4){cout << "stack(int n = 4)" << endl;_a = new T[n];_top = 0;_capacity = n;}~stack(){cout << "~stack()" << endl;delete _a;_a = nullptr;_top = _capacity = 0;}private:T* _a;int _top;int _capacity;
};如果想声明和定义分离这样写
但模板一般声明和定义都是在一个文件写的 不会分开写 因为会产生链接错误
暂且先不讲 我在模板进阶再详细说
template<class T>
Stack<T>::Stack(int n)
{cout << "Stack(int n = 4)" << endl;_a = new T[n];_top = 0;_capacity = n;
}int main()
{显式实例化stack<int>st;stack<double>st;
}

拿栈来做例子,C语言里面如果栈里面要存int和double类型数据 还要typedef 成intdatatype 或者doubledatatype 还要把类型名改成stackint 或者stackdouble

而有了类模板以后就避免了这种低效用法,直接显式实例化要存的类型数据,类模板参数直接推演出对应存储数据类型。

类模板的实例化

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

#include<iostream>
#include<vector>
#include<stack>
using namespace std;int main()
{vector是类名  vector<int>才是类型vector<int>s;同理stack是类名  stack<double>才是类型stack<double>st;return 0;
}

总结:普通类----类名是类型   类模板----类名<数据类型>才是整个类的类型。

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

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

相关文章

最优算法100例之30-表示数值的字符串

专栏主页&#xff1a;计算机专业基础知识总结&#xff08;适用于期末复习考研刷题求职面试&#xff09;系列文章https://blog.csdn.net/seeker1994/category_12585732.html 题目描述 请实现一个函数用来判断字符串是否表示数值&#xff08;包括整数和小数&#xff09;。例如&a…

基于ArrayList实现简单洗牌

前言 在之前的那篇文章中&#xff0c;我们已经认识了顺序表—>http://t.csdnimg.cn/2I3fE 基于此&#xff0c;便好理解ArrayList和后面的洗牌游戏了。 什么是ArrayList? ArrayList底层是一段连续的空间&#xff0c;并且可以动态扩容&#xff0c;是一个动态类型的顺序表&…

Java方法的参数传递机制与递归总结

文章目录 1、方法的参数传递机制1.1、形参和实参1.2、 参数传递机制&#xff1a;值传递1.3、 举例1.4 练习 2、 递归(recursion)方法 1、方法的参数传递机制 1.1、形参和实参 若方法含有参数&#xff1a; 形参&#xff08;formal parameter&#xff09;&#xff1a;在定义方…

QT背景介绍

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、QT背景 1.1什么是QT 1.2QT的发展历史 1.3什么是框架、库 1.4QT支持的平台 1.5QT的优点 1.6QT的…

BIM转Power BI数据集

在本博客中&#xff0c;我们将了解如何使用从 SSAS 表格、Power BI Desktop 或 Power BI 服务数据集中提取的 Model.bim 文件在本地或 PBI 服务上生成新数据集。 1、设置&#xff08;SSAS 表格和 PBI 服务通用&#xff09; 我建议你创建一个专门用于此任务的新 Python 环境&a…

old photo老照片图像复原数据集

来源 本来想拿DA-CLIP 训练一下old photo&#xff0c;训练代码没成功&#xff0c;毕设没时间就不研究了 github搜old photo复原论文原作者好像没开源训练数据集&#xff0c;所以用了这个SynOld 训练集500对测试集200对 但是readme写的很差&#xff0c;其他什么也没交代 展示…

Centos-Linux安装部署MySQL-8.0

linux搭建mysql 1.使用系统的root账户 2.切换到 /usr/local 目录下 3.下载mysql wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.31-linux-glibc2.12-x86_64.tar.xz也可以直接在官方下载最新版本 官方下载 选择linux 4.解压mysql tar xvJf mysql-8.0.21-l…

C易错注意之const修饰指针,含char类型计算,位段及相关经典易错例题

目录 前言 一&#xff1a;const修饰指针 1.const修饰变量 2.const 修饰指针 1.const int*p&m; 2. int* const p&m; 3. int const *p&m; 4. int const *const p&m; 5.总结 总之一句话为&#xff1a;左定值有定向 二&#xff1a;关于计算中char类型…

C语言:动态内存管理(二)

目录 前言 1.3 realloc​编辑 3、常见动态内存管理错误 3.1 对空指针的解引用操作 3.2 对动态开辟的空间进行越界访问 3.3 对非动态开辟内存使用free释放 3.4 使用free释放一块动态内存开辟的一部分 3.5 对同一块空间的多次释放 3.6 动态内存开辟之后忘记释放 总结 前…

杨氏矩阵(C语言)

文章目录 问题技术名词解释思路关键代码运行代码 问题 有一个数字矩阵&#xff0c;矩阵的每行从左到右是递增的&#xff0c;矩阵从上到下是递增的&#xff0c;请编写程序在这样的矩阵中查找某个数字是否存在。 要求&#xff1a;时间复杂度小于O(N); 技术名词解释 杨氏矩阵&…

自动化测试框架Robot Framework入门

什么是RF RF是一个基于 Python 的、可扩展的关键字驱动的自动化 验收测试框架、验收测试驱动开发 &#xff08;ATDD&#xff09;、 行为驱动开发 &#xff08;BDD&#xff09; 和机器人流程自动化 &#xff08;RPA&#xff09;。它 可用于分布式、异构环境&#xff0c;其中自动…

Spring Security——04,认证_校验

认证_校验 一、认证过滤器二、配置过滤器三、测试过滤器3.1 登录接口3.2 非登录接口3.3 结果 一键三连有没有捏~~ 一、认证过滤器 创建一个filter包&#xff0c;创建一个过滤器 代码如下&#xff1a; Component public class JwtAuthenticationTokenFilter extends OncePerR…

在集群中使用deepspeed如果端口被占用可以使用deepspeed参数更改

在集群中使用deepspeed如果端口被占用可以使用deepspeed参数更改 这一次G老师不好使了 在集群中使用deepspeed默认的端口号29500被占用&#xff0c;显示更改居然不起作用 G老师给的方法也不好使 #!/bin/bash MASTER_ADDRlocalhost MASTER_PORT29501 # 选择一个未被占用的端…

mysql 运算符 语句 字符集 校队集

mysql 运算符 使用select语句可以输出运算的结果 mysql标识符不区分大小写 算数运算符 1./除法 得到的结果是一个小数 %是整数,省略小数 2、除以0不会报错,得到的结果是 null 3.数宇和字符串做加法运算,并不会拼接 比较运算符 1.mysql里面的=是比较运算符,而不是赋值运算…

lora pingpang系统 4

1 深入了解LoRa技术原理 1.1 LoRa扩频通信原理 1.1.1 模拟无线通信&#xff1a; 模拟无线通信是一种使用模拟信号传输数据的通信方式。这种通信方式已经被数字无线通信所取代&#xff0c;因为数字通信具有更高的效率和可靠性。 天线&#xff1a;从空中接收到的无线电波转换成…

数据结构——图的概念,图的存储结构,图的遍历(dfs,bfs)

目录 1.图的定义和术语 2.案例引入 1.六度空间理论 3.图的类型定义 4.图的存储结构 1.邻接矩阵 1.无向图的邻接矩阵表示法 2.有向图的邻接矩阵表示法 3.网&#xff08;有权图&#xff09;的邻接矩阵表示法 代码示例&#xff1a; 2.采用邻接矩阵表示法创建无向图…

MySQL 表的增删改查

文章目录 一、什么是CRUD&#xff1f;二、新增&#xff08;Create&#xff09;1、单行数据 全列插入2、多行数据 指定列插入3、插入特殊类型 三、查询&#xff08;Retrieve&#xff09;1、全列查询2、指定列查询3、表达式查询4、指定别名5、去重6、排序7、条件查询基本查询&a…

java算法day44 | ● 完全背包 ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ

完全背包理论基础 完全背包和01背包问题唯一不同的地方就是&#xff0c;每种物品有无限件。 体现在代码中就是对背包的遍历顺序不同。01背包是逆序遍历背包&#xff0c;完全背包是顺序遍历背包。 518. 零钱兑换 II class Solution {public int change(int amount, int[] coin…

IMAP的要点:旅行前需要了解的内容

你是否经常因会议而出差&#xff0c;需要在各种设备上灵活地访问你的电子邮件&#xff1f;如果是的话&#xff0c;你可能会想了解你的电子邮件系统是如何通过使用互联网消息访问协议&#xff08;IMAP&#xff09;来工作的&#xff0c;这样当你不在办公桌前时&#xff0c;你可以…

Java基础 - 代码练习

第一题&#xff1a;集合的运用&#xff08;幸存者&#xff09; public class demo1 {public static void main(String[] args) {ArrayList<Integer> array new ArrayList<>(); //一百个囚犯存放在array集合中Random r new Random();for (int i 0; i < 100; …