函数模板与类模板初阶

如果要写一个交换函数,不同类型的话调用不同的交换函数,如果使用重载的话只能解决函数名相同但是会根据参数类型调用不同的函数。即使这样也依旧要写很多不同类型的swap交换函数

函数重载的交换函数

仔细观察会发现除了类型不同其他的函数结构什么的都一样,都是定义中间变量,然后用它作为过渡交换其他的两个变量。因此可以用C++模版的知识,告诉编译器一个模子,让编译器根据不同类型 利用该模子来生成代码。其实本质上还是写了三个函数,只是模版是让编译器帮你写而已。

通俗点讲就是让编译器往这个模具中填充不同的材料(类型),来获得不同材料的产品(即生成具体的代码)

模板分为两个部分,函数模板和类模板

函数模板

函数模板是函数形式的模板,在编译器编译阶段,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用,需要什么,编译器帮助你实例化你要的函数,比如:当用double类型使用函数模板时,编译器根据传过来参数的类型进行推演,讲实参确定为double类型,然后产生一份专门处理double类型的代码。对于别的类型,比如int它也会直接推演成int类型的函数,本质上还是写了函数,只是编译器自动帮你干了。

函数模板格式

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

用swap举例子就是

#include<iostream>
using namespace std;template<typename T>
void swap1(T& a, T& b)
{T c = a;a = b;b = c;
}int main()
{int a = 3; int b = 7;swap1(a,b);cout << a << endl;cout << b << endl;
}

 

但是我为什么写模板swap要写成swap1,这是因为编译器把一些常用的函数已经写成了函数,swap就是其中之一,所以你再写一个swap交换模板就会报错

 函数模板的实例化

 模板参数实例化分为:隐式实例化和显示实例化,隐式实例化就是和上面swap1模板调用一样不告诉编译器要什么类型swap(a,b),让编译器自己根据实参类型去推演。而显式实例化是告诉了编译器要让模板生成什么类型的函数,基本方式为在函数名后的<>中指定模板参数的实际类型

同样依旧是swap1函数显示实例化的样子

如果传的参数是不同的类型的,编译器会怎么去推演呢,比如add模板,我用一个int类型+double类型会怎么样呢

隐式调用模板

从上图可以看出隐式调用模板会直接报错,因为编译器不知道把T推演出int类型还是double类型 

解决办法是把其中一个强制转换成另一个一样的类型,比如把double装换成int类型,但是这样一定会发生精度的丢失

#include<iostream>
using namespace std;template<typename T>
T add(const T& a, const T& b)
{return a + b;
}int main()
{int a = 3; double b = 7.5;int ret = add(a, (int)b);//把double类型强制转换成int类型cout << ret<< endl;
}

但是为什么这里函数形参为什么都加上const呢,把const删了会依旧找不到add,会报错

这是因为类型转换实际上也会产生临时变量进行过渡,double类型强转int转换过程会丢弃浮点数的小数部分。这意味着,无论小数点后的数字是什么,都会被直接忽略。这个过程被称为截断。截断后的整数部分被赋值给一个 int 类型的临时变量(如果这是显式转换的结果)。这个临时变量是编译器在内部生成的,用于存储转换后的整数值。

因为是临时变量具有常性,int引用实际上引用的是这个临时变量,所以要加const

第二种方法是模板T类型直接用改成两个,一个传int类型,一个传double类型。也就是将template<typename T>改成template<typename T1,typename T2>; 但是究竟传什么类型回来呢,难点在于我并不知道返回的究竟是T1还是T2,所以返回值直接用auto修饰,让编译器自己去推导就可以解决了

#include<iostream>
using namespace std;template<typename T1, typename T2>
auto add(const T1& a, const T2& b)
{return a + b;
}int main()
{int a = 3; double b = 7.5;int ret = add(a, (int)b);cout << ret<< endl;
}

第三种办法就是显示实例化

 总结一下如果有不同的类型的参数调函数模板,无论怎样都要进行强制类型转换,都会造成精度的丢失

模板参数匹配规则

如果既有普通的函数又有函数模板推导并且普通函数参数和调用的地方实参类型对应的上的话,那么编译器会优先调用普通函数(优先匹配普通函数+参数匹配)

 如果没有普通的函数或者普通的函数参数和实参类型对应不上的话,会去优先匹配参数类型对应的上的函数模板

总结一下就是先普通函数然后模板函数

类模板格式

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

 

// 动态顺序表
// 注意: Vector 不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template < class T >
class Vector
{
public :
Vector ( size_t capacity = 10 )
: _pData ( new T [ capacity ])
, _size ( 0 )
, _capacity ( capacity )
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector ();
void PushBack ( const T & data )
void PopBack ()
// ...
size_t Size () { return _size ;}
T & operator []( size_t pos )
{
assert ( pos < _size );
return _pData [ pos ];
}
private :
T * _pData ;
size_t _size ;
size_t _capacity ;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template < class T >
Vector < T > :: ~Vector ()
{
if ( _pData )
delete [] _pData ;
_size = _capacity = 0 ;
}

通俗点类模板只是使类成员成为模板类型而已,可一个也可以所有都成为模板类型。

 类模板实例化

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

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

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

相关文章

编程新手必看,Python3中继承知识点及语法学习总结(28)

1、继承 在Python 3中&#xff0c;继承是面向对象编程的一个核心概念&#xff0c;它允许我们创建一个新的类&#xff08;称为子类或派生类&#xff09;&#xff0c;该类继承另一个类&#xff08;称为父类或基类&#xff09;的属性和方法。通过这种方式&#xff0c;子类可以重用…

Linux下基本指令-掌握

目录 为什么要学命令行 Linux下基本指令-掌握 ls 指令 pwd命令 cd 指令 touch指令 mkdir指令&#xff08;重要&#xff09;&#xff1a; rmdir指令 && rm 指令&#xff08;重要&#xff09;&#xff1a; man指令&#xff08;重要&#xff09;&#xff1a; cp指…

ThingsBoard远程RPC调用设备

使用 RPC 功能 客户端 RPC 从设备发送客户端 RPC 平台处理客户端RPC 服务器端 RPC 服务器端RPC结构 发送服务器端RPC 使用 RPC 功能 ThingsBoard 允许您从服务器端应用程序向设备发送远程过程调用 (RPC)&#xff0c;反之亦然。基本上&#xff0c;此功能允许您向设备发送命…

【Flutter】自动生成图片资源索引插件二:FlutterAssetsGenerator

介绍 FlutterAssetsGenerator 插件 &#xff1a;没乱码&#xff0c;生成的图片索引命名是小驼峰 目录 介绍一、安装二、使用 一、安装 1.安装FlutterAssetsGenerator 插件 生成的资源索引类可以修改名字&#xff0c;我这里改成R 2. 根目录下创建assets/images 3. 点击image…

HPE Aruba Networking推出新一代Wi-Fi 7接入点 助力企业高效应对安全、AI与物联网挑战

HPE ArubaNetworking推出的全新Wi-Fi 7接入点&#xff0c;提供全面的AI就绪边缘IT解决方案&#xff0c;旨在为用户和物联网设备提供安全、高性能的连接服务&#xff0c;以实现数据的捕获和路由&#xff0c;从而满足AI训练和推理需求 休斯顿-2024年4月23日-慧与科技(NYSE: HPE)近…

Python浅谈清朝秋海棠叶版图

1、清朝疆域概述&#xff1a; 清朝是我国最后一个封建王朝&#xff0c;其始于1616年建州女真部努尔哈赤建立后金&#xff0c;此后统一女真各部、东北地区。后又降服漠南蒙古&#xff0c;1644年入关打败农民起义军、灭南明&#xff0c;削三藩&#xff0c;复台湾。后又收外蒙&am…

el-input-number 只能输入整数,最小值1,最大值5

<el-form-item label"排序" prop"name" > <el-input-number v-model"form.sort" placeholder"请输入唯一排序" :min1 :max"5" :precision"0" class"custom-input-number" /> </el-form-…

addr2line + objdump 定位crash问题

目录 背景 godbolt汇编工具 tombstone ARM平台汇编知识 寄存器介绍 常见汇编指令 函数入参及传递返回值过程 入参顺序 变参函数 虚函数表 典型问题分析过程 Crash BackTrace Addr2line objdump 拓展 为什么SetCameraId函数地址偏移是40(0x28) 参考 背景 最近在…

新兴游戏引擎Godot vs. 主流游戏引擎Unity和虚幻引擎,以及版本控制工具Perforce Helix Core如何与其高效集成

游戏行业出现一个新生事物——Godot&#xff0c;一个免费且开源的2D和3D游戏引擎。曾经由Unity和虚幻引擎&#xff08;Unreal Engine&#xff09;等巨头主导的领域如今迎来了竞争对手。随着最近“独特”定价模式的变化&#xff0c;越来越多的独立开发者和小型开发团队倾向于选择…

目前软件测试前景怎么样?有哪些机遇和挑战?

随着信息技术的快速发展&#xff0c;软件已经成为了我们生活中不可或缺的一部分。而软件的质量和稳定性也直接关系到用户的使用体验和企业的竞争力。因此&#xff0c;软件测试作为软件质量保证的重要环节&#xff0c;其前景也备受关注。 首先&#xff0c;从行业角度来看&#x…

javaEE--多线程学习-进程调度

进程调度不明白&#xff1f;看这一篇文章就够了&#xff0c;逻辑衔接严密&#xff0c;文末附有关键面试题&#xff0c;一个海后的小故事让你瞬间明白这里面的弯弯绕绕&#xff01; 目录 1.什么是进程&#xff1f; 2.进程控制块&#xff08;PCB&#xff09; 2.1 一个PCB就是一…

python中开发页面的两种方法:Qt Designer(PyQt图形化界面拖拽开发App界面)以及Django(开发Web应用框架)

一、开发独立的窗口&#xff0c;App的那种&#xff0c;可使用tkinter或者PyQt 使用PyQt时&#xff0c;里面有个工具Qt Designer&#xff0c;是一个可视化的界面设计工具&#xff0c;可以通过拖拽等方式来设计界面。下面就是Qt Designer的操作界面&#xff1a; 参考链接如下&am…