11 Qt模板库Qt模板库(QTTemplateLibrary简称QTL)是一套提供对象容器的模板。如果你的编译器没有适当的STL(标准模板库)可用,QTL将被代替使用。QTL提供了对象的链表、对象的矢量(动态数组)、从一个类型到另一个类型的映射(或称为字典)和相关的迭代器和算法。一个容器是包含和管理其它对象的一个对象,并且提供迭代器对被包含的对象进行访问。Qt模板类说明如表2。表2 Qt模板类说明模板类名称说明QMap提供基于值的一个字典的模板类QMapConstIteratorQMap的常量迭代器QMapIteratorQMap的迭代器QPair提供基于值的一对元素的模板类QValueList提供基于值的一个双向链表的模板类QValueListConstIteratorQValueList的常量迭代器QValueListIteratorQValueList的迭代器QValueStack提供基于值的一个堆栈模板类QValueVector提供基于值的一个动态数组模板类QTL类的命名约定与其他Qt类一致(比如,count()、isEmpty())。它们还提供额外的函数来兼容STL算法,比如size()和empty()。可以像使用STL的函数map一样来使用它们。与STL相比,QTL仅仅包含了STL容器应用程序接口的最重要的特性,没有平台差异,通常要慢一些并且经常扩展为更少的对象代码。如果你不想拷贝存储对象,你最好使用QPtrCollection及派生类。它们就是被设计用来处理各种类指针的。QObject没有拷贝构造函数,因此QObject不能作为一个值使用。但可以存储指向QObject的指针到QValueList。当然,直接使用QPtrList更好。QPtrList像所有其它的基于QPtrCollection的容器一样,提供了比速度优化了、基于值的容器更多健全的检查。如果你有一些使用值的对象,并且在你的目标平台没有可用的STL,Qt模板库就可以替代它。使用值的对象至少需要一个拷贝构造函数、一个赋值操作符和一个默认构造函数(如:一个没有任何参数的构造函数)。注意一个快速的拷贝构造函数对于容器的高性能是关键的,因为许多拷贝操作将会发生。如果你想排序你的数据,你必须在你的数据类中实现operator()。Qt模板库是为高性能而设计,迭代器是非常快的。为了实现这样的性能,Qt模板库比基于QPtrCollection的集合类做更少的错误检查。一个QTL容器,例如:QTL容器没有跟踪任何相关的迭代器。这样在诸如删除条目时没有执行有效性检查,但它提供了很好的执行性能。11.1迭代器(Iterators)Qt模板库打交道的是值对象,而不是指针对象。迭代器是最好的遍历容器方法。遍历一个容器可使用像下面的循环:typedefQValueListintList;Listl;for(List::Iteratorit=l.begin();it!=l.end();++it)printf(Numberis%i\n,*it);begin()返回第一个元素的迭代器,end()返回的是最后一个元素之后的一个迭代器。end()标明的是一个无效的位置,它永远不能被解除引用。它只是任何一次迭代的终止条件,迭代可以从begin()或end()开始。同样的概念也适用于其它容器类,例如,用于QMap和QValueVector的迭代方法如下:typedefQMapQString,QStringMap;Mapmap;for(Map::iteratorit=map.begin();it!=map.end();++it)printf(Key=%sData=%s\n,it.key().ascii(),it.data().ascii());typedefQValueVectorintVector;Vectorvec;for(Vector::iteratorit=vec.begin();it!=vec.end();++it)printf(Data=%d\n,*it);11.2算法Qt模板库定义了大量操作容器的算法。这些算法用模板库函数实现,还提供了有迭代器的容器的通用代码。例如:qHeapSort()和qBubbleSort()提供了著名的堆排序和冒泡排序算法。你可以象下面这样使用它们:typedefQValueListintList;Listl;l421001234128;qHeapSort(l);Listl2;l2421001234128;List::Iteratorb=l2.find(100);List::Iteratore=l2.find(8);qHeapSort(b,e);doublearr[]={3.2,5.6,8.9};qHeapSort(arr,arr+3);第一个例子对整个列表排序。第二个例子对两个迭代器之间的所有元素排序,即100、1234和12。第三个例子表明迭代器是作为指针使用的。一些常用的模板函数说明如下:(1)函数qSwap()用来交换两个变量的值,例如:QStringsecond(Einstein);QStringname(Albert);qSwap(second,name);(2)函数qCount()用于统计容器中一个值出现的次数。例如:QValueListintl;l.push_back(1);//放入1到l链表中l.push_back(1);l.push_back(1);l.push_back(2);intc=0;qCount(l.begin(),l.end(),1,c);//统计1的个数c,c=3(3)函数qFind()用于查找容器中一个值的第一次出现位置。例如:QValueListintl;l.push_back(1);l.push_back(1);l.push_back(1);l.push_back(2); //查找2所在的位置QValueListIteratorintit=qFind(l.begin(),l.end(),2);(4)函数qFill()用于将一个值拷贝填充到一个范围。例如:QValueVectorintv(3);qFill(v.begin(),v.end(),99);//将99填充整个v数组,v包含99,99,99(5)函数qEqual()用来比较两个范围的元素是否相等,两个范围的元素个数不一定相等。只要第一个范围的元素与第二个范围的对应元素都相等时,就认为这两个范围相等。例如:QValueVectorintv1(3);v1[0]=1;v1[2]=2;v1[3]=3;QValueVectorintv2(5);v1[0]=1;v1[2]=2;v1[3]=3;v1[4]=4;v1[5]=5;boolb=qEqual(v1.begin(),v2.end(),v2.begin());//b==TRUE(6)函数qCopy()用于拷贝一个范围的元素到输出迭代器,例如:QValueListintl;l.push_back(100);l.push_back(200);l.push_back(300);QTextOStreamstr(stdout); //拷贝l中所有元素到输出迭代器QTextOStreamIteratorqCopy(l.begin(),l.end(),QTextOStreamIterator(str));(7)函数qCopyBackward()用于拷贝一个容器或者它的一部分到一个输出迭代器,拷贝的次序是从后面开始,例如:QValueVectorintvec(3);vec.push_back(100);vec.push_back(200);vec.push_back(300);QValueVectorintanother; //“another”包含的是按倒序排列的(300、200、100)。qCopyBackward(vec.begin(),vec.end(),another.begin());如果你写了新的算法,请考虑把它们写成模板函数,这样就可以使它们能够用在尽可能多的容器上了。在上一个例子中,你可以很容易地使用qCopy()打印出一个标准C++数组,方法列出如下:intarr[]={100,200,300};QTextOStreamstr(stdout);qCopy(arr,arr+3,QTextOStreamIterator(str));11.3数据流串行化所有提到的容器(如:QValueList、QStringList、QValueStack和QMap等)都可被相应的流操作符串行化。下面是一个例子。QDataStreamstr(...);QValueListQRectl;//……在这里填充这个列表strl;容器还能象下面这样被再一次读入:QValueListQRectl;strl;12 集合类一个集合类是装有多个条目的容器,每个条目是某种数据结构,集合类能执行对容器中的条目的插入、删除及查找等操作。Qt有几个基于值和基于指针的集合类。基于指针的集合类使用指向条目的指针来工作,而基于值的集合类存储着它们条目的拷贝。基于值的集合类类似于STL容器类,能和STL算法和容器一起使用。基于值的集合类说明如表4所示:表4 基于值的集合类表类名称说明QValueList基于值的链表QValueVector基于值的矢量结构QValueStack基于值的栈结构QMap基于值的字典结构基于指针的集合类说明如表5所示:表5 基于指针的集合类表类名称说明QCache和QIntCacheLRU(leastrecentlyused)缓存结构。QDict、QIntDict和QPtrDict字典结构。QPtrList双向链接的链表结构。QPtrQueueFIFO先进先出(firstin,firstout)队列结构。QPtrStackLIFO后进先出(lastin,firstout)栈结构。QPtrVector矢量结构。QMemArray是一个例外,它既不是基于指针也不是基于值,而是基于内存的结构。用于在有简单数据结构的数组中使用QMemArray效率最高,QMemArray在拷贝和数组元素比较时使用位逻辑运算符操作。这些类中有一些具有迭代器,迭代器是遍历集合类中的条目的类。在Qt模板库里,基于值的集合和算法集成在一起。下面讨论基于指针的容器。12.1基于指针的容器的结构基于指针的容器有4个内部基类(QGCache,QGDict,QGList和QGVector)操作void类型指针。通过增加/删除条目指针,一个由这4个类组成的薄模板层实现了实际的集合。允许Qt的模板类的策略使得在空间上很经济(实现这些模板类仅增加了对基类的内联调用),而且还不影响执行效率。示例:QPtrList使用下面的例子说明了如何存储Employee条目到一个链表,并将它们以相反的次序打印出来。#includeqptrlist.h#includeqstring.h#includestdio.hclassEmployee{public:Employee(constchar*name,intsalary){n=name;s=salary;}constchar*name()const{returnn;}intsalary()const{returns;}private:QStringn;ints;};intmain(){QPtrListEmployeelist;//指向Employee的指针链表。list.setAutoDelete(TRUE);//当链表条目被移动时,删除条目。list.append(newEmployee(Bill,50000)); //链表追加新的对象。list.append(newEmployee(Steve,80000));list.append(newEmployee(Ron,60000));QPtrListIte