Qt提供了两种类型的容器类:序列容器和关联容器。例如QVector<T>,QLinkedList<T>和QList<T>属于序列容器,而QMap<K,T>和QHash<K,T>属于关联容器。
Qt提供了通用的算法,对这些容器类执行一些操作,如qSort()对一个序列容器进行排序,而qBinaryFind()在一个排过序的序列容器内执行二叉树查找。
序列容器
QVector<T>是一个类数组的数据结构,与C++中普通的数组不同之外是:一个向量知道本身的大小并可被重置大小。将一个向量的末尾添加一个新的项相当有效,而往其前面或中间插入一个项则代价比较昂贵。
用法:
在提前知道大小的情况下:
QVector<double>vect(3);
vect[0]= 1.0;
vect[1]= 0.540302;
vect[2]= -0.416147;
在大小不可知的情况下:
QVector<double>vect;
vect.append(1.0);
vect.append(0.540302);
vect.append(-0.416147);
或
vect<< 1.0 << 0.540302 << -0.416147;
遍历一个向量:
doublesum = 0.0;
for(int i = 0; i < vect.count(); ++i)
sum+= vect[i];
QLinkedList<T>是一个链表数据结构,它不支持随机访问,但可以很高效的完成插入和删除操作。链表是通过迭代子来访问的。链表的使用如下所示:
QLinkedList<QString>list;
list.append("Clash");
list.append("Ramones");
QLinkedList<QString>::iteratori = list.find("Ramones");
list.insert(i,"Tote Hosen");
QList<T>结合了QVector<T>和QLinkedList<T>的优点,是一个“数组-链表”,它的接口是基于索引的,它是一个最合适的通用容器类。
QStack<T>和QQueue<T>是两个更实用的子类。QStack<T>在向量的基础上增加了push(),pop()和top()方法,而QQueue<T>在链表的基础上增加了enqueue(),dequeue()和head()方法。
说明:对于所有的容器类,类型T可以是基本的数据类型,如整型或双精度型,指针类型或一个拥有默认构造函数,一个拷贝函数和一个赋值操作符的类,这些类包括QByteArray,QDateTime,QRegExp,QString和QVariant。从QObject类中继承的子类不能作为窗口类的项,因为它们的拷贝函数和赋值操作符被禁用了。
解决办法(Trick):将指向这些对象的指针作为容器类的项,而不是对象本身。
T也可以是一个容器类,但在写法上要注意:
QList<QVector<double>> list;
如上,两个>之间一定要有空格,否则编译会将其解释为>>而导致出错。
容器的遍历——迭代器
Java风格的迭代器:只读和读写迭代器。只读迭代器类有QVectorIterator<T>,QLinkedListIterator<T>和QListItrator<T>,相应的读写迭代器在名字中有个Mutable,如QMutableVectorIterator<T>
使用Java风格的迭代器时要注意,迭代子并不直接指向容器中的项,它们可定位在第一项之前,最后一项之后或两者之间,如下所示:
QList<double>list;
...QListIterator<double> i(list);
while(i.hasNext()) {
do_something(i.next());
}
注:在Java风格的只读迭代器中,可以直接对容器进行操作,无需一份拷贝,这些细节已经由相应的类自动完成了,如:
QListIterator<int>i(splitter->sizes());
while(i.hasNext()) {
do_something(i.next());
}
STL风格的迭代器;
只读:QVector<T>::iterator,读写:QVector<T>::const_iterator。
如:
QList<int>list = splitter->sizes();
QList<int>::const_iteratori = list.begin();
while(i != list.end()) {
do_something(*i);
++i;
}
注意,在STL风格下,我们只能对容器的拷贝进行迭代。
//错误写法:
while(i != splitter->sizes().end()) {
do_something(*i);
++i;
}
隐式共享
由于存在隐式共享,拷贝一个容器类代价并不高,与复制一个指针的代价差不多。仅当某个容器的拷贝内容发生变化时才进行真正的拷贝,有点像Linux中父过程与子进程之间的“写时复制”共享数据。隐式共享鼓励对象通过传值的方式返回。
Qt中所有的容器类以及许多其他的类都使用了隐式共享,包括QByteArray,Qbrush, AFont, QImage,QPixmap和QString。这些类通过传值的方式传递时非常高效,不管是作为函数参数或是作为函数返回值。
隐式共享保证了数据只有被修改时才会进行真正的复制。所以在Qt中,尽管使用只读形式的接口。
关联容器
Qt提供了两个主要的关联容器类:QMap<K,T>和QHash<K,T>。
访问方式如下代码所示:
写
QMap<QString,int> map;
map.insert("eins",1);
map.insert("sieben",7);
map.insert("dreiundzwanzig",23);
或
map["eins"]= 1;
map["sieben"]= 7;
map["dreiundzwanzig"]= 23;
读
intval = map.value("dreiundzwanzig");
或
intseconds = map.value("delay", 30);带默认值。
QMultiMap是一种1对多的映射容器。
QHash与QMap的接口类似,不过它是无序的,它也有一个变体QMultiHash。
通用算法
<QtAlgorithms>包含了一些通用的全局模板函数,实现了操作于容器类数据的通用算法。
如qFind(),qCopy(), qFill(), qSort()等。
类容器类
与容器类有许多共性的三个类是:QString, QByteArray, QVariant。
QString的值是16位Unicode值,包含ASCII和Latin-1。QString可认为是一个元素为QChar类型的向量,它可嵌入’\0’,length()函数返回的值包含嵌入的’\0’。QString支持+和+=连接字符串,也可以使用append()方式。也可以使用sprintf()方法连接不同的字符串,如:
str.sprintf("%s%.1f%%", "perfect competition", 100.0);
显示地将一个constchar*型字符串转换为QString类型的方法如下:
constchar* str = “This is a test”;
QStringqstr = (QString)str;
或qstr= QStirng::fromLocal8Bit_helper(str)或qstr= QString::fromLatin1();
将QString转变为constchar*型的步骤如下:
先使用toLocal8Bit()或toLatin1()返回一个QByteArray类型的对象
使用QByteArray::data()或QByteArray::constData()将其转换为constchar*型。
QString与中文显示问题
QString本身是支持中文显示的,它默认是支持unicode的。要使QString能正常地显示中文,必须传递合适的unicode。有两种方法:
利用QTextCodec的toUnicode()方法。
如:w.setWindowTitle(QTextCodec::codecForName("gb2312")->toUnicode("这是一个测试!"));
利用QTextCodec的静态方法,如setCodecForCStrings等。
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));
优先选择第二种方法。