c++模板初阶----函数模板与类模板

目录

泛型编程

 函数模板

函数模板的概念

函数模板的格式

函数模板的原理 

函数模板的实例化

函数模板的匹配原则

类模板

类模板的定义格式

类模板的实例化


c++的模板大致可以分为:

  1. 函数模板
  2. 类模板

 首先在我们引入模板之前,先进行介绍泛型编程

泛型编程

在c语言中如果让你写一个swap函数

那么在c语言中我们可以这样写

// 交换两个整型
void swap_int(int* p1, int* p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
// 交换两个双精度浮点型
void swap_double(double* p1, double* p2)
{double tmp = *p1;*p1 = *p2;*p2 = tmp;
}

在c++中我们知道由函数重载这一特点,但是在c语言中这并没有,所以在对应不同类型的值进行交换时,会对应要有对应的函数。并且要注意进行址传递,而不是值传递。

而在后来的c++引入函数重载后,swap又可以进行这样的书写代码

// 交换两个整型
void swap(int& p1, int& p2)
{int tmp = p1;p1 = p2;p2 = tmp;
}
// 交换两个双精度浮点型
void swap(double& p1, double& p2)
{double tmp = p1;p1 = p2;p2 = tmp;
}

C++的函数重载使得用于交换不同类型变量的函数可以拥有相同的函数名,并且传参使用引用传参,使得代码看起来不那么晦涩难懂。

但是即使这样设计,还是有不足之处

 1:重载的多个函数仅仅只是类型不同,代码的复用率比较低,只要出现新的类型需要交换,就需要新增对应的重载函数。

2、代码的可维护性比较低,其中一个重载函数出现错误可能意味着所有的重载函数都出现了错误。

那么是否存在一种模板,使得我们无论要交换什么类型,他都可以让编译器根据不同的类型利用该模子来生成相应的代码呢?

 就像涂鸦石膏一样,已经给出了一个标准的模具,我们使用不同的颜色进行涂鸦,就可以得到不同颜色的石膏奥特曼。

如果在C++中,也能够存在这样一个模具,通过给这个模具填充不同颜色的材料(类型),从而得到形状相同但颜色不同的石膏(生成具体类型的代码),那将会大大减少代码的冗余。巧的是前人早已将树栽好,我们只需在此乘凉。

答案是存在的,也就是后来c++祖师爷所创建的c++的模板;

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

 

 函数模板

函数模板的概念

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

函数模板的格式

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

就比如用swap举例:

template<class T>
void swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}

注意:typename是用来定义模板参数的关键字,也可以用class代替,但是不能用struct代替。

函数模板的原理 

那么函数模板的底层原理是什么呢?就拿现代的人工智能来说,

客户服务:聊天机器人和虚拟助手可以自动处理客户查询、提供帮助和支持,减轻人工客服的压力。早期的时候,这其实就是先给机器人一个对应固定回复模板来进行聊天。

马云:世界是懒人创造的

这句话是一种幽默的说法,意思是人类会创造出各种方便的工具和技术来减少工作量,从而变得“懒惰”。实际上,人类通过创造和发明来提高效率,创造更好的生活条件,并不一定代表懒惰。我们的创造力和创新精神推动着社会的发展和进步。

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

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

函数模板的实例化

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

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

#include<iostream>
using namespace std;
template<class T>
void Swap(T& x, T& y)//注意不能用swap,因为引用了using namespace std;标准库里面存在标准的库函数swap
{T tmp = x;x = y;y = tmp;
}
int main()
{int a = 10, b = 20;cout << "a=" << a << " " <<  "b=" << b << endl;Swap(a, b);cout << "a=" << a << " " << "b=" << b << endl;return 0;
}

运行结果:

我们在此基础上进行略微修改 

其实修改后是编译不通过的。

因为在编译期间,编译器根据实参推演模板参数的实际类型时,根据实参a将T推演为int,根据实参b将T推演为double,但是模板参数列表中只有一个T,编译器无法确定此处应该将T确定为int还是double。
 此时,我们有两种处理方式,第一种就是我们在传参时将b强制转换为int类型,第二种就是使用下面说到的显示实例化。

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

#include<iostream>
using namespace std;
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = 10;double b = 20;int c = Add<int>(a, b); //指定模板参数的实际类型为intcout << c;return 0;
}

运行结果:

 注意:使用显示实例化时,如果传入的参数类型与模板参数类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功,则编译器将会报错。

就比如:

#include<iostream>
using namespace std;
template<class T>
void Swap(T& x,T& y)
{T tmp = x;x = y;y = tmp;
}
int main()
{int a = 10;double b = 20;cout << "a=" << a << " " <<  "b=" << b << endl;Swap<int>(a, b);cout << "a=" << a << " " << "b=" << b << endl;return 0;
}

观察仔细的话可以发现我们这里没有用const修饰,这就是其中一个问题。

因为b要进行隐式类型转化,如果不加const的话,那么就会存在权限放大的错误。

但是加上const的话又会报错,不能修改其值。

所以来说不是所有的都是要加const,不是所有都可以及进行要进行隐式类型转化的显示实例化;

函数模板的匹配原则

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

#include <iostream>
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{return x + y;
}
//通用类型加法的函数模板
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = 10, b = 20;int c = Add(a, b); //调用非模板函数,编译器不需要实例化int d = Add<int>(a, b); //调用编译器实例化的Add函数return 0;
}

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

#include <iostream>
using namespace std;
//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{return x + y;
}
//通用类型加法的函数模板
template<typename T1, typename T2>
T1 Add(const T1& x, const T2& y)
{return x + y;
}
int main()
{int a = Add(10, 20); //与非模板函数完全匹配,不需要函数模板实例化int b = Add(2.2, 2); //函数模板可以生成更加匹配的版本,编译器会根据实参生成更加匹配的Add函数return 0;
}

 三、模板函数在隐式实例化不允许自动类型转换,但普通函数可以进行自动类型转换

#include <iostream>
using namespace std;
template<typename T>
T Add(const T& x, const T& y)
{return x + y;
}
int main()
{int a = Add(2, 2.2); //模板函数不允许自动类型转换,不能通过编译return 0;
}

编译无法通过,因为模板函数不允许自动类型转换,所以不会将2自动转换为2.0,或是将2.2自动转换为2。

类模板

类模板的定义格式

template<class T1,class T2,…,class Tn>
class 类模板名
{
private://类内成员声明
};

就比如:

#include<iostream>
using namespace std;
template<class T>
class A
{
public:A(T val) :a(val){}void print(){cout << a << endl;}
private:T a;
};
int main()
{A<int> a(2);a.print();return 0;
}

运行结果:

 注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。

#include<iostream>
using namespace std;
template<class T>
class A
{
public:A(T val) :a(val){}void print();
private:T a;
};
template<class T>
void A<T>::print()
{cout << a << endl;
}
int main()
{A<int> a(2);a.print();return 0;
}

类模板的实例化

 类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面根<>,然后将实例化的类型放在<>中即可。

注意:类模板名字不是真正的类,而实例化的结果才是真正的类。

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

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

相关文章

期权黑天鹅怎么应对?近期很有可能发生的事情!

今天带你了解期权黑天鹅怎么应对&#xff1f;在当今世界&#xff0c;投资者们不断地寻找着各种策略来应对市场的波动和不确定性。其中&#xff0c;黑天鹅策略在近年来逐渐受到了广泛的关注&#xff0c;这种策略主要是利用极端事件&#xff0c;例如突发事件或自然灾害等难以预测…

【React笔记初学总结一】React新手的学习流程笔记总结,掰开了揉碎了,下载安装基础结构学习

REACT学习记录 一、React是什么&#xff1a;二、尝试安装下载&#xff1a;三、理解都有什么四、基础网页学习&#xff1a;1.几个比较重要的资源包例子2.第一个react示例&#xff1a;&#xff08;掰开了揉碎了&#xff0c;咱们先看懂它最简单的结构&#xff09;3.第二个react示例…

C++链接FTP服务器并下载数据(在qt中编写)

.pro文件 #------------------------------------------------- # # Project created by QtCreator 2024-07-16T13:19:03 # #-------------------------------------------------QT core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT widgetsTARGET untitled TE…

Qt实现IP地址输入框-自定义控件

在 许多应用程序中&#xff0c;我们经常需要使用IP地址。为了方便用户输入和处理&#xff0c;一个好的解决方案是使用自定义控件。本示例代码使用Qt编写一个名为“IPAddress”的自定义控件来实现IP地址的输入功能。通过使用此控件&#xff0c;用户可以方便地输入和处理IP地址。…

吴恩达机器学习笔记 三十八 二进制标签 均值归一化

标签 0 和 1 可以有很多种意义。从回归到二分分类&#xff1a;之前定义 ,而对于二进制标签&#xff0c;通过给出y^(i,j)为 1 的概率&#xff0c;其中 损失函数 均值归一化 计算每个电影的平均得分&#xff0c;例如第一部电影的平均分为2.5&#xff0c;第五部电影的平均分为1.2…

如何在excel表中实现单元格满足条件时整行变色?

可以试试使用条件格式&#xff1a; 一、条件格式 所谓“自动变色”就要使用条件格式。 先简单模拟数据如下&#xff0c; 按 B列数字为偶数 为条件&#xff0c;整行标记为蓝色背景色。 可以这样设置&#xff1a; 先选中1:10行数据&#xff0c;在这里要确定一下名称栏里显示…

pico+unity3d手部动画

在 Unity 开发中&#xff0c;输入系统的选择和运用对于实现丰富的交互体验至关重要。本文将深入探讨 Unity 中的 Input System 和 XR Input Subsystem 这两种不同的输入系统&#xff0c;并详细介绍它们在控制手部动画方面的应用。 一、Input System 和 XR Input Subsystem 的区…

Java性能优化-书写高质量SQL的建议(如何做Mysql优化)

场景 Mysql中varchar类型数字排序不对踩坑记录&#xff1a; Mysql中varchar类型数字排序不对踩坑记录_mysql vachar排序有问题-CSDN博客 为避免开发过程中针对mysql语句的写法再次踩坑&#xff0c;总结开发过程中常用书写高质量sql的一些建议。 注&#xff1a; 博客&#…

Java面试题--JVM大厂篇之深入解析JVM中的Serial GC:工作原理与代际区别

目录 引言&#xff1a; 正文&#xff1a; 一、Serial GC工作原理 年轻代垃圾回收&#xff08;Minor GC&#xff09;&#xff1a; 老年代垃圾回收&#xff08;Major GC或Full GC&#xff09;&#xff1a; 二、年轻代和老年代的区别 年轻代&#xff08;Young Generation&a…

docker快速安装(环境CentOS7)

1. 查看自己的Linux系统 cat /etc/redhat-release 2. 安装依赖插件 yum -y install gcc yum -y install gcc-c yum install -y yum-utils yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo yum makecache fast yum -y insta…

MongoDB常用命令大全,概述、备份恢复

文章目录 一、MongoDB简介二、服务启动停止、连接三、数据库相关四、集合操作五、文档操作六、数据备份与恢复/导入导出数据6.1 mongodump备份数据库6.2 mongorestore还原数据库6.3 mongoexport导出表 或 表中部分字段6.4 mongoimport导入表 或 表中部分字段 七、其他常用命令八…

养猪管理如何实现远程监控

在现代化农业快速发展的背景下&#xff0c;养猪管理的智能化与远程监控技术的应用日益成为提升养殖效率、保障动物健康及优化资源配置的关键手段。实现养猪管理的远程监控&#xff0c;不仅能够实时掌握猪场环境参数与生猪生长状况&#xff0c;还能有效预防疾病、提高生产性能&a…

Spring Cloud环境搭建

&#x1f3a5; 个人主页&#xff1a;Dikz12&#x1f525;个人专栏&#xff1a;Spring学习之路&#x1f4d5;格言&#xff1a;吾愚多不敏&#xff0c;而愿加学欢迎大家&#x1f44d;点赞✍评论⭐收藏 目录 1. 开发环境安装 1.1 安装JDK ​1.2 安装MySQL 2. 案列介绍 2.1 …

C语言指针超详解——进阶篇

C语言指针系列文章目录 入门篇 强化篇 进阶篇 文章目录 C语言指针系列文章目录1. 字符指针变量2. 数组指针变量2. 1 概念2. 2 数组指针变量的初始化 3. 二维数组传参的本质4. 函数指针变量4. 1 函数指针变量的创建4. 2 指针变量的使用4. 3 两个有趣的代码4. 3. 1 代码一4. 3. …

汽车底盘控制系统Autosar初步接触

最近接触到汽车底盘控制部分&#xff0c;作为小白&#xff0c;原以为汽车底盘也是要自己手敲代码&#xff0c;结果发现完全不是。记录一下最近的学习心得&#xff0c;初步接触东西不全&#xff0c;但可以当作参考。 对于底盘控制部分的简单理解&#xff1a;simulink做汽车底盘的…

大数据技术基础

一、大数据平台 1.大数据平台方案步骤&#xff1a; ①市场上有哪些大数据平台 ②硬件、系统、业务增长等方面 ③方案是否通过 通过后&#xff1a;按照一期目标投入 先虚拟环境部署联系&#xff0c;再实际部署 《大数据架构介绍》《Hadoop架构解析》《Hadoop集群规划》 《H…

PX4 运行 make px4_sitl_default gazebo 报错

报错原因&#xff1a;最开始我把依赖一直都是在base环境下安装的&#xff0c;没有conda deactivate&#xff0c;而pip install的东西应该装在系统环境&#xff0c;不能装在base环境下&#xff0c;sudo apt 是装在系统环境的 1.检查ros 用鱼香ros安装 wget http://fishros.…

南平建网站公司推荐 好用的b2b独立站模板

床品毛巾wordpress独立站模板 床单、被套、毛巾、抱枕、靠垫、围巾、布艺、枕头、乳胶枕、四件套、浴巾wordpress网站模板。 https://www.jianzhanpress.com/?p4065 打印耗材wordpress自建独立站模板 色带、墨盒、碳粉、打印纸、硒鼓、墨盒、墨水、3D打印机、喷头wordpress…

Pr 2024下载安装,Adobe Premiere pro2024剪辑软件下载合集获取

Premiere Pro 2023中文版简称Pr&#xff0c;pr2023是一款视频编辑软件。 pr 2023不仅可以帮助用户对各种视频进行剪辑、旋转、分割、合并、字幕添加、背景音乐等基础的处理&#xff0c;还能帮助用户进行视频颜色校正、颜色分级、稳定镜头、调整层、更改片段的持续时间和速度、效…

Sentinel规则持久化Push模式两种实现方式

文章目录 sentinel持久化push推模式微服务端的实现具体实现源码分析读数据源写数据源的实现 微服务端解析读数据源流程 修改源码的实现官方demo修改源码实现配置类flowauthoritydegreadparamsystemgateway修改源码 测试补充 前置知识 pull模式 sentinel持久化push推模式 pull拉…