C++模版基础知识与STL基本介绍

目录

一. 泛型编程

二. 函数模板

1. 概念

 2. 函数模版格式

3. 函数模版的原理

4. 模版函数的实例化

(1). 隐式实例化

(2.) 显式实例化

5. 模版参数的匹配原则

三. 类模板

1. 类模板的定义格式

 2. 类模板的实例化

四. STL的介绍

1. 什么是STL?

 2. STL的版本

3. STL的六大组件


一. 泛型编程

我们之前实现一个交换函数,不同的类型就要用多个函数,我们学了函数重载比C语言时期方便了一点,不用想函数名了

如下代码

void Swap(int& xxxx, int& yyyy)
{int temp = xxxx;xxxx = yyyy;yyyy = temp;
}
void Swap(double& xxxx, double& yyyy)
{double temp = xxxx;xxxx = yyyy;yyyy = temp;
}
void Swap(char& xxxx, char& yyyy)
{char temp = xxxx;xxxx = yyyy;yyyy = temp;
}

但是呢,仍然有很多不好的地方:

1. 重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数

2. 代码的可维护性比较低,一个出错可能所有的重载均出错

那么能不能告诉编译器一个模子,让编译器根据不同类型利用模子来生成代码呢?

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

二. 函数模板

1. 概念

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

 2. 函数模版格式

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

返回值类型  函数名 (参数列表) {}

如以下代码所示

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

typename 是用来定义模板参数关键字也可以使用class(尤其注意:不要用struct替代class)

如下

template <class T>
void Swap(T& xxxx, T& yyyy)
{T temp = xxxx;xxxx = yyyy;yyyy = temp;
}
3. 函数模版的原理

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

 在编译器编译阶段,对于模版函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用

假如主函数代码如下

int  main()
{int x1 = 1;int y1 = 32;Swap(x1, y1);return 0;
}

int 类型推演

处理代码为

void Swap(int& xxxx, int& yyyy)
{int temp = xxxx;xxxx = yyyy;yyyy = temp;
}

假如主函数内容如下

int  main()
{char x2 = 11;char y2 = 33;Swap(x2, y2);return 0;
}

char类型推演

处理代码为

void Swap(char& xxxx, char& yyyy)
{char temp = xxxx;xxxx = yyyy;yyyy = temp;
}

当用 double 类型使用函数模版时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码

4. 模版函数的实例化

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

(1). 隐式实例化

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

#include<iostream>
using namespace std;template <typename T>
T Add(const T& left, const T& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;Add(a1,d1 );Add(a2, d2);
return 0;
}

上述代码不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型

通过实参a1将T推演为int ,通过实参d1将T推演为double类型,但模版参数列表中只有一个T,编译器无法确定此处到底该将T确定为int或double类型而报错 

注意:在模版中,编译器一般不会进行类型转换操作,因为一旦转换出问题,编译器就需要背黑锅

此时有两种解决方法:1. 用户手动强制类型转换 2.  使用显式实例化

Add(a1,(int)d1);
Add((double)a2,d2);
(2.) 显式实例化

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

int main()
{int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;Add<int>(a1,d1 );Add<double>(a2, d2);return 0;
}

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

5. 模版参数的匹配原则

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

如以下代码

#include<iostream>
using namespace std;
template <typename T>
T Add(const T& left, const T& right)
{return left + right;
}
int Add(const int& x, const int& y)
{return (x + y) * 10;
}int main()
{int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;cout << Add(1, 2) << endl;cout << Add<int>(2, 2) << endl;
}

其结果为

 我们发现,与若与非模板函数匹配,编译器不需要特化

若显式实例化则调用编译器特化的Add版本

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

#include<iostream>
using namespace std;int Add(const int& x, const int& y)
{return (x + y) * 10;
}
template <typename T1,class T2>
T2 Add(const T1& left, const T2& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;cout << Add(1, 2) << endl;cout << Add(1, 2.1) << endl;return 0;
}

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

template <typename T1>
T1 Add(const T1& left, const T1& right)
{return left + right;
}
int main()
{int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;char c1 = 'a';Add(1, 2.1);Add(d1, c1);
}

第一个Add函数 2.1不会自动转换为int类型,1也不会自动转换为double(或float)

第二个同理 d1不会自动转化为char .......

而普通函数可以

#include<iostream>
using namespace std;int Add(const int& x, const int& y)
{return (x + y) * 10;
}int main()
{float a=10.11;int a1 = 10, a2 = 11;double d1 = 11.11, d2 = 7.007;char c1 = 'a';Add(1, 2.1);Add(d1, c1);
}

 第一个Add函数2.1 自动进行了类型转换变为int类型

第二个Add函数的d1 自动类型转换变为了int类型,c1也转化为了int类型

三. 类模板

1. 类模板的定义格式

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

 如下代码

#include<iostream>
#include<cstring>
using namespace std;template <typename T>
class Stack
{
public:Stack(size_t capacity = 4):_arr(new T[capacity]),_capacity(capacity),_size(0){}void Push(const T& data){if (_size == _capacity){T* tmp = new T [_capacity*2];memcpy(tmp, _arr, sizeof(T)*_size);delete[] _arr;_arr = tmp;_capacity *= 2;}_arr[_size++] = data;}T Top(){return _arr[_size-1];}~Stack(){delete[] _arr;_arr = nullptr; _size = _capacity = 0;}
private:T* _arr;size_t _capacity;size_t _size;
};

而类的成员函数要在类外实现时需要注意

再写一个模板,因为类上面的模版只针对类内

假如 将Push类内声明,类外定义,代码如下

class Stack
{
public:Stack(size_t capacity = 4):_arr(new T[capacity]),_capacity(capacity),_size(0){}void Push(const T& data);T Top(){return _arr[_size-1];}~Stack(){delete[] _arr;_arr = nullptr; _size = _capacity = 0;}
private:T* _arr;size_t _capacity;size_t _size;
};template <typename T>
void Stack<T>::Push(const T& data)
{if (_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _arr, sizeof(T) * _size);delete[] _arr;_arr = tmp;_capacity *= 2;}_arr[_size++] = data;
}
int main()
{Stack<int> s1;s1.Push(1);cout << s1.Top() << endl;s1.Push(5);cout << s1.Top() << endl;s1.Push(12);cout << s1.Top() << endl;s1.Push(11);cout << s1.Top() << endl;s1.Push(2);cout << s1.Top() << endl;s1.Push(3);cout << s1.Top() << endl;return 0;
}

下面的模板参数 也可以不叫T ,这两个T实际上就是代号,为什么是Stack<T>:: ,可以看下一条模板的实例化

模板不建议,声明和定义分离到两个文件.h 和.cpp 会出现链接错误,具体原因后面会讲

 2. 类模板的实例化

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

	
//其中Stack是类名,Stack<int>、Stack<char>、Stack<double>才是类型Stack<int> s1;Stack<double> s2;Stack<char> s3;

四. STL的介绍

1. 什么是STL?

STL(standard template libaray-标准模板库): 是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。

 2. STL的版本
  • 原始版本

Alexander Stepanov、Meng Lee 在惠普实验室完成的原始版本,本着开源精神,他们声明允许 任何人任意运用、拷贝、修改、传播、商业使用这些代码,无需付费。唯一的条件就是也需要向原 始版本一样做开源使用。 HP 版本--所有STL实现版本的始祖。

  • P.J.版本

由P. J. Plauger开发,继承自HP版本,被Windows Visual C++采用,不能公开或修改,缺陷:可读 性比较低,符号命名比较怪异。

  • RW版本

由Rouge Wage公司开发,继承自HP版本,被C+ + Builder 采用,不能公开或修改,可读性一 般。

  • SGI版本

由Silicon Graphics Computer Systems,Inc公司开发,继承自HP版 本。被GCC(Linux)采用,可 移植性好,可公开、修改甚至贩卖,从命名风格和编程 风格上看,阅读性非常高。

3. STL的六大组件

 


这篇文章就写到这里啦,喜欢点一下赞吧~~

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

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

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

相关文章

Docker学习与实战

一、Docker安装 移除旧版本docker sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine配置docker yum源 sudo yum install -y yum-utils配置阿里云docker仓库 sudo y…

Windows按钮快捷键解释(有摸鱼技巧!):(个人尝试)另外警告:仅代表UP建议,不一定适用于所有电脑!谨慎尝试哦~好好工作!杜绝摸鱼!引以为戒!

哈喽&#xff01;各位好&#xff0c;我们来一期电脑专题的&#xff08;快捷键&#xff09;第一次尝试&#xff0c;你们看看吧&#xff01; 警告&#xff1a;仅代表UP建议&#xff0c;不一定适用于所有电脑&#xff01;谨慎尝试哦~好好工作&#xff01;杜绝摸鱼&#xff01; 一…

Internxt:适用于Linux开源安全云存储平台

有无数的云存储平台为您的文件提供安全可靠的存储空间。可在 Linux 上安装的热门云存储应用程序包括Dropbox、Nextcloud和Google Drive&#xff0c;遗憾的是&#xff0c;后者迄今为止不提供 Linux 客户端。 其他自托管选项包括OwnCloud、Pydio Cells、Seafile、Resilio和Synct…

修改Kolla项目中的REPO地址

部署 社区驱动版OpenStack时&#xff0c;Kolla-ansible工具可以一键部署 podman、docker、Containerd、LXD 等 容器的运行环境&#xff0c;默认情况下 Kolla-ansible 中指定的 repository 地址都是上述产品的 official 地址&#xff0c;这些地址在私有化场景中、甚至中国大陆的…

解决:Sentinel设置blockHandler不生效,只有fallback生效

解决&#xff1a;Sentinel设置blockHandler不生效&#xff0c;只有fallback生效 一个人经验总结&#xff1a;二官方文档&#xff1a;三SentinelResource注解&#xff1a;用法示例 一个人经验总结&#xff1a; 二官方文档&#xff1a; 三SentinelResource注解&#xff1a;用法示…

gitkraken报displaying 2000 commits, adjust this setting in preference的错误

1.主要原因是目录下存在未知的软链接,而gitkraken在面对这种软链接时会报错. 2.解决办法是通过终端指令的方式,先commit当前的内容,然后切换到以前不包含软链接的分支上,在提交新代码时,忽视掉软链接所在的文件夹,再提交代码就行了. 3.终端指令的有关内容为到.git所在的目录,…

Diffutoon下载介绍:真人视频转动漫工具,轻松获得上千点赞

最近在刷短视频的时候&#xff0c;偶尔能看到一些真人转动漫风的作品&#xff0c;看起来给人一种新鲜感&#xff0c;流量都还不错&#xff0c;简简单单跳个舞&#xff0c;就能获得上千个点赞~ 那么&#xff0c;这种视频是怎么制作的&#xff1f; 本期给大家介绍一款AI转绘工具…

【秋招笔试题】小O的01矩阵

输入 2 2 01 10 10 01 2 01 01 11 00 输出 2 -1解析&#xff1a;此题看到数据范围&#xff0c;直接DFS暴力即可&#xff0c;暴力枚举每行每列是否需要翻转&#xff0c;因为翻转两次是没有意义的。 #include <iostream> #include <cstring> #include <algorithm…

vue3 tree组件slots特性实践

上一小节我们实现了SvgIcon组件来支持组件开发中用到字体图标的地方&#xff0c;并应用在了tree节点折叠、展开的图标上&#xff0c;本小节我们将其用到tree的插槽内容中&#xff0c;一起来学习基于Vue3 tsx的插槽用法吧~ 先看要实现的效果&#xff1a; 要实现的文档部分&…

C嘎嘎浅谈模板

这篇文章给大家介绍一下c嘎嘎内存管理和模板&#xff0c;那么我们直接进入正题 c/c的程序内存分布 这里的了解一下即可 new和delete的定义和操作 格式&#xff1a;类型* 对象名 new 类型&#xff1b; 数组(对象)定义格式&#xff1a;类型* 对象名 new 类型[元素个数]&…

【机器学习】智驭未来:机器学习如何重塑制造业的转型与升级

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀目录 &#x1f50d;1. 引言&#x1f4d2;2. 机器学习重塑制造业生产流程&#x1f338;预测性维护&#xff1a;减少停机时间&#xff0c;提高设…

简单快捷!Yarn的安装与使用指南

Yarn 是由 Facebook (现 Meta) 开发的包管理工具。 今天&#xff0c;我将介绍如何使用 Yarn。 目录 Yarn 的官方网站 关于安装 版本确认 开始一个新项目&#xff08;创建 package.json 文件&#xff09; 安装软件包 升级包 运行脚本 执行包的命令 卸载包 总结 Yarn 的…

【MySQL进阶之路 | 高级篇】简述Bin Log日志

1. 日志类型 MySQL有不同类型的日志文件&#xff0c;用来存储不同类型的日志&#xff0c;分为二进制日志、错误日志、通用查询日志和慢查询日志&#xff0c;这也是常用的4种。MySQL 8又新增两种支持的日志:中继日志和数据定义语句日志。使用这些日志文件&#xff0c;可以查看M…

exo-tinggrad 架构解析

目录 exo-tinggrad 架构解析 8B 模型配置 70B 模型配置 exo-tinggrad 架构解析 这个项目目录包含了一系列与Python相关的文件和文件夹,它们共同构成了一个可能的项目或库。这些文件和文件夹按照特定的命名和组织方式被放置在了一起,以便于管理、开发和维护。 tinygrad: 这…

解决:Nacos无法获取远程配置数据,导致项目启动各种配置异常

解决&#xff1a;Nacos无法获取远程配置数据&#xff0c;导致项目启动各种配置异常 一问题描述&#xff1a;1.项目pom依赖版本&#xff1a;2.bootstrap.yml配置信息3.远程配置&#xff1a;默认public命名空间4.启动报异常&#xff0c;显示没有配置数据源&#xff0c;实际远程已…

金字塔监督在人脸反欺骗中的应用

介绍 论文地址&#xff1a;https://arxiv.org/pdf/2011.12032.pdf 近年来&#xff0c;人脸识别技术越来越普及。在智能手机解锁和进出机场时&#xff0c;理所当然地会用到它。人脸识别也有望被用于管理今年奥运会的相关人员。但与此同时&#xff0c;人们对人脸欺骗的关注度也…

邦布带你从零开始实现图书管理系统(java版)

今天我们来从零开始实现图书管理系统。 图书管理系统 来看我们的具体的实现&#xff0c;上述视频。 我们首先来实现框架&#xff0c;我们要实现图书管理系统&#xff0c;首先要搭框架。 我们首先定义一个书包&#xff0c;在书包中定义一个书类和一个书架类&#xff0c;再定义…

51单片机15(直流电机实验)

一、序言&#xff1a;我们知道在单片机当中&#xff0c;直流电机的控制也是非常多的&#xff0c;所以有必要了解一些这个电机相关的一些知识&#xff0c;以及如何使用单片机来控制这个电机&#xff0c;那么在没有学习PWM之前&#xff0c;我们先简单的使用GPIO这个管脚来控制电机…

女人内裤怎么洗才是最干净?内衣裤洗衣机怎么样?哪个牌子更好?

最近刚好用到一款比较好用的洗内衣裤洗衣机&#xff01;如果你也和我一样有洗内衣裤烦恼的&#xff0c;或者可以看看&#xff01; 内衣裤作为贴身穿的衣服&#xff0c;我是不会把它和外衣一起清洗的&#xff0c;而家里面的大洗衣机已经担起了清洗外衣的工作&#xff01; 朋友们…

jdk的major version和minor version是啥意思?

写在前面 1&#xff1a;正文 major version是大版本号&#xff0c;minor version是小版本号&#xff0c;但目前minor version都是0&#xff08;也可能是我没有发现&#x1f605;&#xff09;&#xff0c;如jdk8就是52&#xff0c;如下表&#xff1a; 可以看到jdk版本号和ma…