C++
- 知识基础
- 流操作符
- 类 & 基础
- 初始化和重载
- 类 & 高级
- 继承和多态
- 模板 & 标准模板库STL
在函数重载我们会遇到两个函数除了某些形参类型不同外,其余包括操作步骤,形参数量等完全一致;使用重载显然是复杂的,所以提出了模板的概念!
一、模板
在设计过程中出现的与数据类型无关的过程,不论什么数据类型,都有相同的操作集合,可以定义模板–>仅仅描述函数/类的结构,编译系统不会为模板产生任何可执行代码!
1.函数模板
函数模板的定义:
template<类型参数表>
返回值类型 函数名(形参列表){
函数体;
}
/*例*********************************************************/
template<class T>
T square(T number){
return number*number;
}
template
关键字:模板定义的开始符;
<类型参数列表>
:说明模板中可能出现的数据类型种类,使用逗号区分多个类型。以class或typename 参数名,~ 声明,一个参数名代表一种不同的数据类型!
模板函数
:在之后的函数中,逻辑意义上可以替换的所有数据类型都用类型参数列表中的参数名表示!
- 在编译器进行函数调用时,对模板函数,才在内存中创建一个函数实例,根据传递的实参类型和返回值确定模板中的参数数据类型如何替换,完成函数任务。
- 模板的定义必须出现在调用之前!
- 在模板使用操作符时,如果传入的参数是用户自定义的对象类型,必须要保证该类重载了使用到的操作符!
- 函数模板支持重载!
2.类模板
定义方式与函数模板类似,首先在类定义之前加上template关键字,声明数据类型参数列表,然后将整个类中参数类型使用到的地方进行替换!
- 在实例化模板类的时候,实例化模板类,必须要指明传递给类模板的数据类型;
template <class T>
class test{
T data;
数据成员;
函数成员;
}
/**定义函数成员*********/
test<T>::test(){//这里对于模板类的使用一定要指明“类名<模板类型>”
构造函数;
}
- 模板类同样支持继承!
- 模板类对象的创建必须指明传递给类模板的数据类型,并放在尖括号中;
test<int>t; //定义了一个test类的对象,并且是int类型的
/***继承***********/
class sub_test:public test<T>{//继承自父类
sub_test(int s):test<T>(s){//调用的是父类的构造函数,初始化父类
构造函数;
}
}
二、标准模板库STL
标准模板库(Standard Template Library)是一个C++提供的程序库,包含了常用的数据结构和算法,体现了软件的复用性。我们从它的三个组成部分进行介绍!
1.容器类(Container)
容器类是管理序列的类,容纳一组对象的类,通过容器类提供的成员函数,可以实现向序列中插入、删除、查找元素等操作。
顺序容器:
-
vector
:矢量容器,容器后面快速插入删除,直接访问任何元素,基于数组!
动态数组,自动调整所占内存的大小,常见操作:
#include <iostream>
#include <vector>
using namespace std;
int main(){
//创建容器
vector<int> t1; //空
vector<int> t2(10); //创建初始总容量10的容器
vector<int> t3(10,1); //创建初始总容量10的容器每个元素的值都为1(可以是变量)
vector<int> t4(t2); //通过存储元素类型相同的其它vector 创建新的vector
//赋值 初始化
t1.assign(3,1); //元素1复制3份加入容器
//添加元素
t1.push_back(elem); //在尾部添加元素
t2.inster(position, elem); //任意位置插入元素(效率低)
//读取元素
t2[0]; //下标运算使用类似数组,list是不支持的
t3.front(); //返回首元素
t3.back(); //返回尾元素
//其他操作
t3.pop_back(); //删除容器尾元素
/*通用的:empty,size,clear,关系运算符等*/
return 0;
}
-
deque
:双端队列容器,容器两端的快速插入删除,直接访问任何元素。
使用类似于vector,内部实现机制和执行性能不同,队头队尾元素出入操作效率高,也可以看作是一个可随机访问的数组;
#include <iostream>
#include <deque>
using namespace std;
-
list
:列表容器,容器任意位置快速插入删除,基于双链表!
使用双向链表实现,适用于经常插入删除元素的场景。
#include <iostream>
#include <list>
using namespace std;
/**list提供了sort成员函数,因为它不是可随机访问的不支持[]**/
以上,三种顺序容器有许多相同的基本成员函数,实现插入删除等基础操作;
关联容器:
这些容器使用映射的方式将元素值与键值相关联,底层采用树形,实现快速操作!
-
set
:集合容器,用于快速查找,不允许重复元素;
-
multiset
:多重集合容器,快速查找,允许重复元素;
这两种容器,集合中的所有的数值就是关键字,不必有另一组值与关键字相关联,其底层数据结构通常为红黑树,可以在对数时间内实现查找、插入、删除,默认元素按照升序排列,以set
为例:
#include<iostream>
#include<set>
using namespace std;
int main(){
//创建容器
set<int> t1; //空
//添加元素
t1.insert(elem);
//查找元素
t1.find(key); //查找键值为key的元素是否存在,返回对应的迭代器
//删除操作
t1.erase(key); //删除键值为key的元素
/*其他的:多重集合中有 count(key) 进行计数*/
return 0;
}
-
map
:映射容器,一对一映射,关键字快速查找,不允许重复值;
-
multimap
:多重映射容器,一对多映射,关键字快速查找,允许重复值;
用于快速存储和读取关键字与关键值,按照关键字排序,以map
为例:
#include<iostream>
#include<map>
using namespace std;
int main(){
//创建容器
map<int, string> t1; //分别指出映射前键的类型 映射后值的类型,创建了一个空map
//添加元素
t1.insert(pair<int, string>(1, "one"));
t1.insert(map<int, string>::value_type<int, string>(1, "two"));
t1[3] = "three"; //注意可以使用下标操作,下标是关键字类型的!
//查找元素
t1.find(key); //查找键值为key的元素是否存在,返回对应的迭代器
//删除操作
t1.erase(key); //删除键值为key的元素
/*其他的:多重集合中有 count(key) 进行计数*/
return 0;
}
容器适配器:
并非独立的容器,依附于一种顺序容器进行功能扩展或限制!
-
stack
:栈,默认使用deque
实现,使用时指明栈中元素类型;
stack<int>s 创建了一个空栈,元素为int型,操作只有s.pop(); s.push(elem);
-
queue
:队列,默认使用deque
实现,使用时指明队列中的元素类型;
queue<int>q 创建了一个空栈,元素为int型,操作只有q.pop(); q.push(elem);
2.迭代器(Iterator)
迭代器提供了顺序访问容器中的每一个元素,不暴露对象内部表示的方法,相当于智能指针,指向容器内部数据,可以通过*
获取值,通过++ --
移动,遍历容器,每个容器中都定义了这样的迭代器,用来存取容器内的值。
容器内关于迭代器的成员:
begin():返回容器中第一个元素的迭代器;
end():返回容器中最后一个元素的迭代器;
find():返回找到的元素的迭代器,否则返回end() 迭代器;
注意:想要接收成员函数返回的迭代器值,要声明相应的迭代器变量
vector<int>::iterator itr = t.begin(); //对迭代器赋值 首元素迭代器
迭代器 五种四级,通过迭代器可以结合 容器 和 泛型算法 ,泛型算法中使用的迭代器做形参,在容器调用时可以特换成某一中指针!
3.泛型算法
实现与容器类型无关的操作,如排序、查询等操作的算法,所有泛型算法的前两个参数是两个迭代器,指示操作在容器中的开始位置 和 结束位置!
template<typename InputIterator,typename T>
InputeIteator find(InputIterator frist,InputInterator last,const T value){
for(;frist != last; ++frist){
if(value == *frist)
return frist;
}
return last;
}
总结
模板只是提高代码复用率的手段而已,对于仅与结构相关的数据结构或者算法有很好的实现效果;所以我们要重点掌握标准模板库中的常用容器的使用,对我们开发有很大的帮助!