c++泛型编程与STL
本文主要针对c++泛型编程 和 STL
相关知识:
1. 模板
-
C++另一种编程思想称为 ==泛型编程== ,主要利用的技术就是模板(可能会造成代码膨胀)
-
C++提供两种模板机制:函数模板( template )和类模板
普通函数与函数模板区别:
-
普通函数调用时可以发生自动类型转换(隐式类型转换)
-
-
如果利用显示指定类型的方式,可以发生隐式类型转换
调用规则如下:
-
如果函数模板和普通函数都可以实现,优先调用普通函数
-
可以通过空模板参数列表来强制调用函数模板
-
函数模板也可以发生重载
-
如果函数模板可以产生更好的匹配,优先调用函数模板
总结:既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性
类模板与函数模板区别主要有两点:
-
类模板只能用显示指定类型方式
-
类模板在模板参数列表中可以有默认参数
类模板中成员函数和普通类中成员函数创建时机是有区别的:
-
普通类中的成员函数一开始就可以创建
-
类模板中的成员函数在调用时才创建
当类模板碰到继承时:如果父类是类模板,子类需要指定出父类中T的数据类型
全局函数类内实现 - 直接在类内声明友元即可
数组模板的实现
1 #pragma once 2 #include <iostream> 3 4 using namespace std; 5 6 template<class T> 7 class MyArray { 8 public: 9 MyArray(int capacity) { 10 this->m_capacity = capacity; 11 m_size = 0; 12 this->pAddress = new T[this->m_capacity]; 13 } 14 15 MyArray(const MyArray& arr) { 16 this->m_capacity = arr.m_capacity; 17 this->m_size = arr.m_size; 18 this->pAddress = new T[this->m_capacity]; 19 for (int i = 0; i < this->m_size; i++) { 20 this->pAddress[i] = arr.pAddress[i]; 21 } 22 } 23 24 MyArray& operator=(const MyArray& arr) { 25 if (this->pAddress != NULL) { 26 delete[] this->pAddress; 27 this->pAddress = NULL; 28 this->m_capacity = 0; 29 this->m_size = 0; 30 } 31 32 this->m_capacity = arr.m_capacity; 33 this->m_size = arr.m_size; 34 this->pAddress = new T[this->m_capacity]; 35 for (int i = 0; i < this->m_size; i++) { 36 this->pAddress[i] = arr.pAddress[i]; 37 } 38 39 return *this; 40 } 41 42 T& operator [](int index) { 43 return this->pAddress[index]; 44 } 45 46 void push_back(const T& val) { 47 if (this->m_capacity == this->m_size) { 48 return; 49 } 50 this->pAddress[this->m_size] = val; 51 this->m_size++; 52 } 53 54 void pop_back() { 55 if (this->m_size == 0) { 56 return; 57 } 58 this->m_size--; 59 } 60 61 int getCapacity() { 62 return this->m_capacity; 63 } 64 65 int getSize() { 66 return this->m_size; 67 } 68 69 ~MyArray() { 70 if (this->pAddress != NULL) { 71 delete[] this->pAddress; 72 this->pAddress = NULL; 73 this->m_capacity = 0; 74 this->m_size = 0; 75 } 76 77 } 78 79 80 private: 81 T* pAddress; 82 int m_capacity; 83 int m_size; 84 };
2. STL初识
面向对象和泛型编程的目的就是复用性的提升
-
-
STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)
-
容器和算法之间通过迭代器进行无缝连接。
-
-
-
算法:各种常用的算法,如sort、find、copy、for_each等
-
迭代器:扮演了容器与算法之间的胶合剂。
-
仿函数:行为类似函数,可作为算法的某种策略。
-
适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
-
容器分为序列式容器和关联式容器
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
算法分为:质变算法和非质变算法。
质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等
非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等
迭代器:容器和算法之间粘合剂
提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
| 功能 | 支持运算 | |
|---|---|---|
| 输入迭代器 | 对数据的只读访问 | 只读,支持++、==、!= |
| 输出迭代器 | 对数据的只写访问 | 只写,支持++ |
| 前向迭代器 | 读写操作,并能向前推进迭代器 | 读写,支持++、==、!= |
| 双向迭代器 | 读写操作,并能向前和向后操作 | 读写,支持++、--, |
| 随机访问迭代器 | 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 |
3.1 string容器
string:是C++风格的字符串,而string本质上是一个类
string和char * 区别:
-
char * 是一个指针
-
string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器。
特点:
string 类内部封装了很多成员方法
例如:查找find,拷贝copy,删除delete 替换replace,插入insert
string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
函数:
isdigit():数字
isalpha():字母
isupper():是否大写
islower():是否小写
tolower():转化为小写
toupper():转化为大写
isspace() isblank(): 空格
ispunct():其他字符
isalnum():判断是否是数字和字母
tolower():转化为小写
使用:
- string构造函数
- string赋值操作:=; assign()
- string字符串拼接:+=; append()
- string 查找和替换:find(); rfind(); replace()
- string 字符串比较:compare()
- string 字符存取:[]; at()
- string 插入和删除:insert(); erase()
- string 字串:substr(0, k);
3.2.vector
单端数组,可以动态拓展(开辟更大的内存空间,拷贝原数据,释放原空间),支持随机访问。
- 构造函数
- 赋值操作 :=; assign()
- 容量和大小:empty(); capacity(); size(); resize()
- 插入和删除:push_back(); pop_back(); insert(); erase(); clear()
- 数据存取:[]; at(); front(); back();
- 互换容器: swap()
- 预留空间:reserve()
- 去重:unique(vec.begin, vec.end)
- 删除:erase(unique(vec.begin, vec.end), vec.end)
3.3 deque
双端数组,降低了访问元素更慢,换来了头部的插入删除效率。支持随机访问。
原理:
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间

- 构造,赋值,大小,数据存取的操作与 vector 一致
- 没有容量的概念
- 插入:多了头部的操作 push_front(); pop_front()
3.4 stack
栈,先进后出
常用接口:
- 数据存取:push(); pop(); top()
- 大小操作:empty(); size()
3.5 queue
队列,先进先出,
常用接口:
- 数据存取:push(); pop(); back(); front()
- 大小:empty(); size()
优先级队列:本质是堆,优先级高的先出。(最大堆,最小堆)
priority_queue,头文件<queue>
语法:priority_queue<Type, Continuer, Functional>
在STL中,默认情况(不加后两个参数)是以vector为容器,以operator< 为比较方式,即优先输出最大的元素。比较方式为greater<int>时,为小顶堆,less<int>为大顶堆(默认)头文件<functional>
成员函数:
| 函数 | 描述 |
| push() | 插入新元素 |
| pop() | 弹出 |
| top() | 取订 |
| size() | 大小 |
| empty() | 判空 |
| swap() | 交换元素 |
| emplace() | 构造并插入元素 |
3.6 list
链表,属于双向迭代器
常用接口:
- 赋值和交换:assign(); =; swap()
- 大小操作:size(); empty(); resize()
- 插入和删除:push_back(); pop_back(); push_front(); pop_front(); insert(); clear(); erase(); remove()
- 数据存取:front(); back()
- 反转和排序:reverse(); sort()
sort()排自定义数据类型时,需要传入“比较器”。
3.7 set/ multiset
集合,所有元素在被插入时会自动排序,属于关联式容器,底层结构是二叉树
multiset 运行出现重复元素。
常用接口:
- 插入与删除:insert(); clear(); erase()
- 大小和交换:size(); empty(); swap()
- 查找和统计:find(); count()
pair 对组创建:建议直接使用构造函数
set 默认从小到大排序,利用仿函数可以改变排序规则
3.8 map / multimap
map 中所有元素都是 pair ,第一个元素是 key, 第二个元素是 value。所有元素会根据 key 自动排序。
属于关联式容器,底层结构是二叉树。
常用接口:
- 大小和交换:size(); empty(); swap()
- 插入和删除:insert(); clear(); erase()
- 查找和统计:find(); count()
4. STL- 函数对象
函数对象 概念:重载函数调用操作符的类,也叫仿函数。
谓词:返回bool 类型的仿函数称为谓词,接收一个参数的叫一元谓词,接收两个参数的叫二元谓词。
内建函数对象(头文件:< functional>)分类:
- 算术仿函数:实现四则运算
- 关系仿函数:大于小于等于
- 逻辑仿函数:与, 或, 非
5. STL- 常用算法
主要包含头文件
- < algorithm >:比较,交换,查找,遍历,复制,修改
- < functional >:定义了一些模板类
- < numeric >:包含了在序列上进行简单数学运算的模板函数
算法:(随机数种子:srand((unsigned int)time(NULL)))
- 遍历算法:for_each(); transform()
- 查找算法:find(); find_if(); adjacent_find(); binary_search(); count(); count_if()
- 排序算法:sort(); random_shuffle(); merge(); reverse()
- 拷贝和替换算法:copy(); replace(); replace_if(); swap()
- 算术生成算法:<numeric> accumulate(); fill()
- 集合算法:set_intersection(); set_union(); set_difference()
sort(vec.begin(), vec.end(), greater<int>())
浙公网安备 33010602011771号