1.型别可作为模板的参数,非型别也可作为模板的参数,如
//#include<bitset>
namespace std
{
template<size_t Bits>
class bitset;
}
如果模板参数不同,具现化所得的模板型别就不同,不能互相赋值或比较
2.缺省模板参数:
template<class T, class container=vector<T> >
class MyClass;
可以传递一个或两个参数使用,缺省参数可以根据前面参数而定义
3.typename作用:
a.定义模板:
template <typename T> class MyClass;
b.指出模板中某个标识符为一种型别,typename不可或缺,C++一般规则是,除了以typename修饰之外,模板内任何标识符都被视为一个值而非型别
template<class T>
class MyClass
{
typename T::SubType * ptr;
}
typename指示SubType为T中的一个型别,如果没有显示指出,SubType会被认为是一个静态成员,并与ptr相乘,SubType在T中必须有相应的性别定义
4.STL的基本观念就是将数据和操作分离。数据由容器类加以管理,操作则由可定制的算法定义之。迭代器在两者之间充当粘合剂,使任何算法都可以和任何容器交互运作
容器可分为两类:
a.序列式容器:此乃可序群集,每个元素有固定位置,和元素值无关,如果以追加方式插入6个元素,排列顺序和插入书序一致,STL定义好的三个序列式容器为vector,deque,list。
a1.vector:头文件:#include<vector>,将元素置于一个dynamic array中加以管理,允许随机存取,但在头部或中间安插或删除比较费时。常用成员函数:push_back(所有序列式容器都提供),size(所有容器都提供)
a2.deque:头文件:#include<deque>,double-ended-queue,是一个dynamic array,可向两端发展,不论在尾部或头部安插元素都很迅速,之间安插时要移动元素。常用成员函数:push_front,push_back,size
a3.list:头文件:#include<list>,由双向链表实作而成,不提供随机存取,但在任何位置上安插或删除都很迅速。常用成员函数:front(返回第一个元素),pop_front(删除第一个元素,但不会返回)
b.关联式容器:此乃已序群集,元素位置取决于特定的排序准则,如果插入6个元素,它们的位置取决于元素值,和插入次序无关。STL定义好的四个关联式容器:set,multiset,map,multimap。所有关联式容器都有insert函数
b1.set:头文件:#include<set>,内部因素依据其值自动排序,每个元素只能出现一次,不允许重复,typedef set<int> IntSet;,缺省以oerator<为排序准则,如果希望以递减排列或是希望用一个完全不同的排序准则,可传入第二个参数,如typedef set<int,greater<int> > Intset;,greater<>是一个预先定义好的仿函数(functor)
b2.multiset:头文件:#include<set>,和set相同,但允许重复;typedef multiset<int> IntMSet;
b3.map: 头文件:#include<map>元素都是实值/键值形成的组,键是排序的基础,每一个键只出现一次,不允许重复,可用make_pair()形成键值对,利用pos->second,pos->first访问pair成员
b4.mulitmap:头文件:#include<map>,和map相同,但也许重复元素,可以包含多个键值相同的元素
除了上述根本的容器类别,为满足特殊要求,C++提供一些特别的Container Adapters,根据基本容器类别实作而成,包括:
stack:头文件#include<stack>,后进先出管理策略
queue:头文件#include<queue>,先进先出管理策略
priority queue:头文件#include<queue>,容器中元素可以拥有不同优先权,下一个元素永远是queue中优先权最高的元素,如果同时又多个因素优先权相同,排序无明确定义,如priority_queue<float> q;
迭代器:指出容器中的一个特定位置,迭代器是个所谓smart pointers,具有遍历复杂数据结构的能力。每一种容器型别都必须提供自己的迭代器。基本操作如下:
operator *
operator ++
operator ==,operator !=
operator =
所以容器类别都提供一些成员函数,获得迭代器并以之遍访所有元素:
begin():容器的起点,即第一个元素的位置
end():最后一个元素之后的位置
任何容器都定义两种迭代器型别:
container::iterator:以读写模式遍历元素
container::const_iterator:以只读模式遍历元素
如:
list<char>::iterator iter;
for(iter=ch.begin();iter!=ch.end();++iter)
cout<<*iter<<" ";
前置++效率较后置++高,后者需要一个临时对象,保存迭代器原本位置并将它返回,一般最好使用++pos,而不是pos++
算法:算法并非容器类别的成员函数,而是一种搭配迭代器使用的全局函数,所有算法只需实作一份,就可对所有容器运作,这里并非面向对象思维模式,而是泛型函数式编程模式,头文件#include<algorithm>
实例1:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<int> coll;
vector<int>::iterator pos;
coll.push_back(9);
coll.push_back(8);
coll.push_back(7);
coll.push_back(10);
pos=min_element(coll.begin(),coll.end());
cout<<"min="<<*pos<<endl;//输出7
cout<<"max="<<*max_element(coll.begin(),coll.end())<<endl;//输出10
for(pos=coll.begin();pos!=coll.end();++pos)
cout<<*pos<<' ';//输出9 8 7 10
cout<<endl;
sort(coll.begin(),coll.end());//缺省按 operator< 排序
for(pos=coll.begin();pos!=coll.end();++pos)
cout<<*pos<<' ';//输出7 8 9 10
pos=find(coll.begin(),coll.end(),8);//如果目标元素8查找失败,返回逾尾迭代器
reverse(coll.begin(),coll.end());//元素反转放置
return 0;
}
实例2:
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
list<int> coll;
for(int i=0;i<6;i++)
{
coll.push_front(i);
coll.push_back(i);
}
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));//输出5 4 3 2 1 0 0 1 2 3 4 5
cout<<endl;
list<int>::iterator end=remove(coll.begin(),coll.end(),3);//remove并没有改变群集中元素数量,end(),size()返回还是当初的值,数值为3的元素被后面元素覆盖了,但位于群集尾端的未被覆盖的元素,原封不动
copy(coll.begin(),end,ostream_iterator<int>(cout," "));//输出5 4 2 1 0 0 1 2 4 5
cout<<endl;
cout<<"number of removed elements:"<<distance(end,coll.end())<<endl;//输出number of removed elements:2,通过测定群集之逻辑终点和实际终点间的距离,获得被删除元素的数量
coll.erase(end,coll.end());//erase可删除所示区间内的全部元素
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));//输出5 4 2 1 0 0 1 2 4 5
//或者采用单一语句删除元素
//coll.erase(remove(coll.begin(),coll.end(),3),coll.end());
return 0;
}