- 泛型程序设计的基本概念
- 泛型程序设计
- 编写不依赖于具体数据类型的数据
- 将算法从特定的数据结构中抽象出来,成为通用的
- C++的模板为泛型程序设计奠定了关键的基础
- 概念
- 用来界定具备一定功能的数据类型
- 对于两个不同的概念A和B,如果概念A所需求的所有功能也是概念B所需求的功能,那么就说概念A是概念B的子概念
- 模型:符合一个概念的数据类型称为该概念的模型
- 泛型程序设计
- 用概念做模板参数名:很多STL的实现代码就是使用概念来命名模板参数的
- STL简介
- 标准模板库(Standard Template Library,简称STL)定义了一套概念体系,为泛型程序设计提供了逻辑基础
- STL中的各个类模板、函数模板的参数都是用这个体系中的概念来规定的
- 使用STL的模板时,类型参数可以是C++标准库中已有的类型,也可以是自定义的类型,只要这些类型是所要求概念的模型
- STL的基本组件
- 容器(container)
- 迭代器(iterator):是算法和容器的桥梁,将迭代器作为算法的参数、通过迭代器来访问容器而不是把容器直接作为算法的参数。
- 函数对象(function object):将函数对象作为算法的参数而不是将函数所执行的运算作为算法的一部分。
- 算法(algorithms)
- 容器
- 容纳、包含一组元素的对象
- 基本容器类模板
- 顺序容器:array(数组)、vector(向量)、deque(双端队列)、forward-list(单链表)、list(链表)
- (有序)关联容器:set(集合)、multiset(双重集合)、map(映射)、multimap(多重映射)
- 无序关联容器:unodered_set(无序集合)、unodered_multiset(无序多重集合)、unodered_map(无序映射)、unodered_multimap(无序多重映射)
- 容器适配器
- Stack(栈)
- Queue(队列)
- Priority-queue(优先队列)
- 迭代器
- 提供了顺序访问容器中每个元素的方法
- 可以使用“++”运算符来获得指向下一个元素的迭代器
- 可以使用“*”运算符来访问迭代器所指向的元素,如果元素类型是类或结构体,还可以通过“—>”来直接访问钙元素的一个成员
- 有些迭代器还支持通过“——”运算符获得上一个元素的迭代器
- 迭代器是泛化的指针,指针也具有同样的特性,因此指针本身就是一种迭代器
- 使用独立于STL容器的迭代器,需要包含头文件<iterator>
- 算法不直接操作容器中的数据,而是通过迭代器间接操作
- 算法和容器独立
- 增加新的算法,无需影响容器的实现
- 增加新的容器,全有的算法也能适用
- 函数对象
- 一个行为类似函数的对象,对他可以像调用函数一样调用
- 函数对象是泛化的函数,任何普通的函数和任何重载了“()”运算符的类的对象都可以作为函数对象使用
- 使用STL的函数对象,需要包含头文件<functional>
- 迭代器支持的操作
- 迭代器是泛化的指针,提供了类似指针的操作(“++”、“*”、“—>”)
- 输入迭代器:可以用来从序列中读取数据,如输入流迭代器
- 输出迭代器:允许向序列中写入数据,如输出流迭代器
- 前向迭代器:既是输出迭代器又是输入迭代器,并且可以对序列进行单向的遍历
- 双向迭代器:与前向迭代器相似,但是在两个方向上都可以对数据遍历
- 随机访问迭代器:也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转,如:使用vector的begin()、end()函数得到的迭代器
- 迭代器的区间
- 两个迭代器表示一个区间:[p1,p2)
- STL算法常以迭代器的区间作为输入,传入数据
- 合法的区间:p1经过n次(n>0)自增(++)操作后满足p1 ==p2
- 区间包含p1,但不包含p2
- 向量
- 特点
- 一个可以扩展的动态数组
- 随机访问,在尾部插入或删除元素快
- 在中间或头部插入或删除元素慢
- 向量的容量
- 容量(capacity):实际分配空间的大小
- S.capacity():返回当前容量
- S.reserve():若容量小于n,则对s进行扩展,使容量至少为n
- 特点
- 双端队列
- 在两端插入或删除元素快
- 在中间插入或删除元素慢
- 随机访问比较快,但比向量容器慢
- 列表
- 特点
- 在任意位置插入和删除元素都很快
- 不支持随机访问
- 接合(splice)操作:s1.splice(p,s2,q1,q2):将s2中的[q1,q2)移动到s1中p所指向元素之前
- 特点
- 单向链表(forward-list)
- 单项链表每个结点只有指向下个结点的指针,没有简单的方法来获取一个结点的前驱
- 未定义insert、emplace和erase操作,而定义了insert-after、emplace-after和erase-after操作,其参数与list的insert、emplace和erase相同,但并不是插入或删除迭代器p1所指的元素,而是对p1所指的元素之后的结点进行操作
- 不支持size操作
- 顺序容器的插入迭代器
- 用于向容器头部、尾部或中间指定位置插入元素的迭代器
- 包括前插迭代器(front_inserter)、后插迭代器(back_inserter)和任意位置插入迭代器(inserter)
- 例: list<int> s; back_inserter iter(s); *(iter++) = 5; //通过iter把5插入s末尾
- 集合(set):集合用来存储一组无重复的元素,由于集合的元素本身是有序的,可以高效的查找指定元素,也可以方便的得到指定大小范围的元素在容器中所处的空间
- 映射(map)
- 映射和集合同属于单重关联容器,他们主要的区别在于,集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组
- 在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定他的存在性之外,还可以得到相应的附加数据
- 多重集合和多重映射
- 多重集合是允许有重复元素的集合,多重映射是允许一个键对应多个附加数据的映射
- 多重集合与集合、多重映射与映射的用法差不多