标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件架构的统称,后续被引入到C++中
在STL编程中,几乎所有的代码都是用采用了模板技术来进行设计,相比于传统编程,这种设计弱化参数类型的概念,使代码具有更好的通用性和重用的机会。
STL编程这种弱化了类型的方式也完全符合泛型编程的概念。
模板
C++中模板是支持“参数化多态”的工具,就是让类或者函数声明为一种通用类型,使得类中的某些成员变量、成员函数的参数、返回值等在实际的使用中可以是任意的类型。模板可以让程序员写出与类型无关的代码,是泛型编程的基础。
模板主要有两种形式:
函数模板
类模板
函数模板
函数模板可以使一个函数的参数和返回值支持通用类型,使此函数专注于算法设计
#include <iostream>
using namespace std;
//模板声明
template <class T>
T add(T a, T b)
{
return a+b;
}
class Dog
{
public:
//运算符重载,仅仅为了让语法通过
friend Dog operator +(const Dog& d1, const Dog& d2);
};
Dog operator +(const Dog&d1, const Dog& d2)
{
Dog d;
return d;
}
int main()
{
string s1 = "AAA";
string s2 = "aaa";
cout << add(s1, s2) << endl;
cout << add(1, 2) << endl;
Dog d1;
Dog d2;
add(d1, d2);
return 0;
}
类模板
#include <iostream>
using namespace std;
//模板声明
template <class T> //class也可以使用typename
class Test
{
private:
T value; //T类型的value(在主函数中定义类型)
public:
Test(T v):value(v){}
T get_value() const
{
return value;
}
void set_value(T v)
{
value = v;
}
};
int main()
{
//创建一个T类型为int的对象
Test<int> t1(123);
t1.set_value(321);
cout << t1.get_value() << endl;
//创建一个T类型为string的Test对象
Test<string> t2("abc");
t2.set_value("xyz");
cout << t2.get_value() << endl;
return 0;
}
类模板声明定义分离
#include <iostream>
using namespace std;
template <class T>
class Test
{
private:
T value;
public:
Test(T v);
T get_value() const;
void set_value(T v);
};
template <class T>//每个类都需声明
Test<T>::Test(T v):value(v){};//构造函数的定义
template <class T>
T Test<T>::get_value() const
{
return value;
}
template <class T>
void Test<T>::set_value(T v)
{
value = v;
}
//主函数和类模板相同
容器
容器是用来存储数据的集合,数据元素可以是任何类型
容器的分类:
顺序容器:string字符串
array数组(C++11)
vector向量
list列表
deque队列
关联容器:map键值对映射
multimap多重键值对映射
容器类的自动申请和释放内存,无需new和delete操作
所有容器使用时都需要引入对应的头文件;string除外
顺序容器中各个元素之间是呈现线性有序分布的,而关联容器没有严格的物理顺序
array数组
此类型是C++11引入的新的容器类型,用于代替传统数组。除了array以外还有顺序容器中各个元素位置并不是固定的,可以通过删除或插入等操作改变后面元素位置
使用时添加#include头文件
//创建一个长度为5的int数组对象
array<int,5> arr = {1,2,3,4};
//赋值
arr[0] = 100;
arr.at(1) = 200;
//遍历
for(int i = 0;i < arr.size();i++)
{
cout << arr.at(i) << " ";
}
cout << endl;
//填充所有元素
arr.fill(6);
for(int i:arr)
{
cout << i << " ";
}
cout << endl;
vector向量
vector是除string外的所有顺序容器中最常用的一种,vector内部使用数组实现,各元素之间的内存是连续的,尽管支持动态长度,但vector更擅长随机存取,不擅长插入和删除操作
头文件!头文件!头文件!#include
创建并判断是否为空:
vector<int> vec1; //创建一个元素为空的向量对象
cout << "是否为空:" << vec1.empty() << endl;
增删改及遍历:
//创建初始元素为5个2的常量对象
vector<int> vec3(5,2);
//向后追加
vec3.push_back(4);
//在第二位置插入元素5
// 参数1:插入位置,begin函数返回值迭代器指针,这个指向第一个元素的位置
// 参数2:插入的元素
vec3.insert(vec3.begin()+1,5);
// 在倒数第二个位置插入元素666
// 此时可以使用end函数获取迭代器指针,此迭代器指针指向的是当前的最后一个元素的后面
vec3.insert(vec3.end()-1,666);
//删除第三个元素
vec3.erase(vec3.begin()+2);
//删除倒数第三个位置的元素
vec3.erase(vec3.end()-3);
//修改第三个元素为3
vec3.at(2) = 3;
//修改第二个元素为222
vec3[1] = 222;
//for-each遍历
for(int i:vec3)
{
cout << i << " ";
}
cout << endl;
list列表
list内部使用双向链表实现,各元素之间的内存不是连续的,虽然元素之间呈线性分布,但是不支持下标操作,只能使用迭代器指针操作。能高效地进行插入删除操作,随机存取的效率较低
list增删改查
头文件!头文件!头文件!#include
list<int> lis;//创建一个元素为空的列表对象
cout << "是否为空:" << lis.empty() << endl;
list<int> lis2(5);//创建一个初始长度为5的列表对象
//创建初始元素为5个2的列表对象
list<int> lis3(5,2);
//向后追加
lis3.push_back(8);
//向前追加
lis3.push_front(666);
//获取最后一个元素和第一个元素
cout << lis3.back() << " " << lis3.front() << endl;
//第二个位置插入元素123
//迭代器指针使用自增或自减来操作
lis3.insert(++lis3.begin(),123);
//在第三个位置插入元素333
//1.先获得头部的迭代器指针对象
list<int>::iterator iter = lis3.begin();
//2.使用固定的函数来移动
advance(iter,2);//后移两下
//插入元素
lis3.insert(iter,333);
//取出第三个元素
iter = lis3.begin();
advance(iter,2);
cout << *iter << endl;
//删除倒数第一个元素
iter = lis3.end();
lis3.erase(--iter);
//修改第一个元素值111
iter = lis3.begin();
*iter = 111;
//排序
lis3.sort();
//因为不支持下标,所以不支持for循环
//for-each
for(int i:lis3)
{
cout << i <<" ";
}
cout << endl;
//清空
lis3.clear();
//大小
cout << lis3.size() << endl;
deque队列
对于接口,deque基本兼容vector和list的接口
从性能上来说,无论插入删除,还是随机存取,其性能都介于vector和list之间,但是由于队列的特性其首位两端的操作比较高效
map键值对映射
map是最常用的一种关联容器,容器之间的各元素之间没有严格的物理顺序,但是其内部仍有某种顺序进行存储,所以支持迭代器遍历
map指的是键值对映射,键key表示元素名称,值value表示元素的数值,一个键绑定一个数据,因此又称键值对
通常键使用的数据类型是字符串,而值的类型根据实际情况制定。键是不可重复的,而值可以重复
头文件!头文件!头文件!#include
//创建一个元素为空的map对象
map<string,int> map1;
cout << "是否为空:" << map1.empty() << endl;
//插入数据
map1["heiget"] = 100;
map1["age"] = 20;
map1["age"] = 25;//修改元素
map1["weiget"] = 77;
map1["sal"] = 4500;
map1.insert(pair<string,int>("id",100001));
//取出某个键对应的值
cout << map1.find("age")->second << endl;
//取出前判断键值对是否存在
if(map1.find("name") != map1.end())
cout << map1.find("name")->second << endl;
else
cout << "没有name键值对!" << endl;
//删除元素
if(map1.erase("sal"))
cout << "删除sal键值对成功!" << endl;
else
cout << "删除sal键值对失败!" << endl;
//清空
map1.clear();
cout << map1.size() << endl;
迭代器
所有容器类型都支持迭代器遍历,iterator是读写迭代器,const_iteratoe是只读迭代器迭代器遍历的性能是最高的
cout << endl << "string关键字" << endl;
string s = "klfneanfaknfen";
for(string::iterator iter = s.begin();iter != s.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << endl << "array数组" << endl;
array<string,6> arr = {"fdfea","awfdwa","af","aef","aefeg"};
for(array<string,6>::iterator iter = arr.begin();
iter != arr.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << endl << "vector向量" << endl;
vector<double> vec(5,1.23);
for(vector<double>::iterator iter = vec.begin();
iter != vec.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << endl << "list列表" << endl;
list<double> lis(5,3.14);
for(list<double>::iterator iter = lis.begin();
iter != lis.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << endl << "deque队列" << endl;
deque<double> deq(5,13.14);
for(deque<double>::iterator iter = deq.begin();
iter != deq.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << endl << "map键值对" << endl;
map<string,string> map1;
map1["name"] = "Jason";
map1["job"] = "salesman";
map1["dept"] = "RD";
for(map<string,string>::iterator iter=map1.begin();
iter!=map1.end();iter++)
{
cout << iter->first << " " << iter->second << endl;
}