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://www.mzph.cn/pingmian/50712.shtml

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

相关文章

3.5-RNN文本生成

1语言模型生成文本的顺序 前面我们已经能够实现使用下图的LSTM网络进行语言建模&#xff1b; 对于一个已经在语料库上学习好的LSTM模型&#xff1b;如果语料库就只是you say goobye and i say hello&#xff1b;那么当把单词i输入到模型中&#xff0c;Time xxx层的第一个LSTM…

苍穹外卖01

0. 配置maven (仅一次的操作 1.项目导入idea 2. 保证nginx服务器运行 &#xff08;nginx.exe要在非中文的目录下&#xff09; 开启服务&#xff1a; start nginx 查看任务进程是否存在&#xff1a; tasklist /fi "imagename eq nginx.exe" 关闭ngi…

中文之美,美在辞藻富丽,也美在情感含蓄内敛。

文章目录 引言句句不提幸福,句句都是幸福句句不提释怀,句句都是释怀句句不提爱意,句句都是爱意句句不提安慰,句句都是安慰句句不提遗憾,句句都是遗憾句句不提思念,句句都是思念引言 许多句子没有将主题直抒胸臆,却通过字词间的呼应、碰撞,让人感受到“言未表而意无穷”…

java高级——Exception异常类基本解读

java高级——Exception异常类基本解读 前情提要文章介绍继承结构异常详解1. 异常的定义2. 异常的分类3.3 异常的处理机制3.3.1 try catch finally语句3.3.2 throw关键字3.3.3 throws关键字 4. 浅谈如何有效的避免异常的发生5. 自定义异常6. 常见的RuntimeException 总结 前情提…

JDBC(Java访问数据库)

Java Database Connectivity&#xff1a;Java访问数据库的解决方案 JDBC定义了一套标准接口&#xff0c;即访问数据库的通用API&#xff0c; 不同的数据库厂商根据各自数据库的特点去实现这些接口。 JDBC希望用相同的方式访问不同的数据库&#xff0c;让具体的数据库操作与数…

HDU1056——HangOver,HDU1057——A New Growth Industry,HDU1058——Humble Numbers

目录 HDU1056——HangOver 题目描述 运行代码 代码思路 HDU1057——A New Growth Industry 题目描述 运行代码 代码思路 HDU1058——Humble Numbers 题目描述 运行代码 代码思路 HDU1056——HangOver 题目描述 Problem - 1056 运行代码 #include <iostream&…

拉提查合创5步玩转git工具协作代码开发

1 工具使用场景 开发团队使用git版本管理工具&#xff0c;进行协作代码开发过程中&#xff0c;最常用的场景为&#xff1a; &#xff08;1&#xff09;拉取代码 将git远端仓库最新代码拉取到本地。 &#xff08;2&#xff09;提交代码 将本地新增修改的代码提交至git远端仓库中…

【SpringBoot】2 项目搭建

创建项目 1&#xff09;确实本地 jdk 版本 打开命令行窗口&#xff1a;快捷键 Windows R&#xff0c;输入 CMD&#xff0c;敲回车 执行命令&#xff1a;java -version 2&#xff09;在项目 clone 的位置创建 Spring Boot 项目&#xff0c;使用 Maven 进行依赖管理&#xff…

大模型学习(1)

初学者&#xff0c;仅做自己学习记录&#xff0c;如果对你有什么帮助&#xff0c;那更好了。 下面是论文《Attention Is All You Need》的经典transformer架构&#xff0c;在学习的过程中&#xff0c;有很多疑惑。 embedding层在做什么 Transformer的embedding层在做的是将输…

35.【C语言】详解函数递归

目录&#xff1a; 定义 作用 例子1~3 拓展学习 趣味练习 1.定义&#xff1a;函数自己调用自己&#xff08;递推回归&#xff09; int main() {main()return 0; } 这样容易死循环&#xff0c;导致爆栈(Stack Overflow) 所以需要设立限制条件&#xff0c;使执行时越来越接近条…

02 Golang面向对象编程_20240727 课程笔记

视频课程 最近发现越来越多的公司在用Golang了&#xff0c;所以精心整理了一套视频教程给大家&#xff0c;这个是其中的第二部&#xff0c;后续还会有很多。 视频已经录制完成&#xff0c;完整目录截图如下&#xff1a; 课程目录 01 结构体的声明.mp402 使用var根据结构体…

iOS基础---多线程:GCD、NSThread、NSOperation

系列文章目录 iOS基础—多线程&#xff1a;GCD、NSThread、NSOperation 文章目录 系列文章目录一、GCD1.GCD的任务、函数、队列a.任务b.函数c.队列 2.GCD的使用a.同步函数并发队列b.异步函数并发队列c.同步函数串行队列d.异步函数串行队列e.同步函数主队列f.异步函数主队列 3.…

FastAPI(七十五)实战开发《在线课程学习系统》接口开发-- 创建课程

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 上次我们分享了&#xff0c;FastAPI&#xff08;七十四&#xff09;实战开发《在线课程学习系统》接口开发-- 删除留言 从本篇文章开始&#xff0c;…

如何学习Doris:糙快猛的大数据之路(从入门到专家)

引言:大数据世界的新玩家 还记得我第一次听说"Doris"这个名字时的情景吗?那是在一个炎热的夏日午后,我正在办公室里为接下来的大数据项目发愁。作为一个刚刚跨行到大数据领域的新手,我感觉自己就像是被丢进了深海的小鱼—周围全是陌生的概念和技术。 就在这时,我的…

嵌入式Python、ROS、SLAM、WebSocket和Node.js:智能巡逻监控安防机器人设计流程(代码示例)

项目概述 随着智能技术的发展&#xff0c;智能巡逻机器人在安防、监控和巡逻等领域的应用越来越广泛。本文将介绍一个结合嵌入式系统、机器人技术和后端开发的智能巡逻机器人。该机器人能够自主导航&#xff0c;实时检测异常情况&#xff08;如火灾或入侵者&#xff09;&#…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十七章 Linux中断实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

AI绘画:艺术与科技融合的新篇章

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;AI绘画作为一种新兴的艺术形式&#xff0c;正逐步改变着传统艺术创作的格局。从早期的简单模仿到如今的个性化创作&#xff0c;AI绘画不仅提升了艺术创作的效率和质量&#xff0c;还开辟了全新的应用场景和商…

C++模板——泛型编程

目录 1. 什么是泛型编程 2. 函数模板 2.1 定义格式 2.2 实例化及原理 2.3 参数匹配原则 3. 类模板 3.1 定义格式 3.2 实例化 4. 非类型模板参数 5. 模板的特化 5.1 概念 5.2 函数模板和类模板特化 6. 模板的分离编译 1. 什么是泛型编程 如何实现一个通用的加…

【Java算法专场】二分查找(下)

目录 山脉数组的峰顶索引 算法分析 算法步骤 算法代码 算法示例 寻找峰值 算法分析 算法步骤 算法代码 算法示例 寻找旋转排序数组中的最小值 算法分析 算法步骤 算法代码 算法示例 点名 算法分析 算法步骤 算法代码 算法示例 山脉数组的峰顶索引 …

TCP/IP协议(全的一b)应用层,数据链层,传输层,网络层,以及面试题

目录 TCP/IP协议介绍 协议是什么,有什么作用? 网络协议为什么要分层 TCP/IP五层网络协议每层的作用 应⽤层 DNS的作用及原理 DNS工作流程 数据链路层 以太⽹帧格式 MAC地址的作用 ARP协议的作⽤ ARP协议的工作流程 MTU以及MTU对 IP / UD / TCP 协议的影响 传输层…