Qt中的容器类


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,QStringQVariant。从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,QPixmapQString。这些类通过传值的方式传递时非常高效,不管是作为函数参数或是作为函数返回值。

隐式共享保证了数据只有被修改时才会进行真正的复制。所以在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对多的映射容器。

QHashQMap的接口类似,不过它是无序的,它也有一个变体QMultiHash


通用算法

<QtAlgorithms>包含了一些通用的全局模板函数,实现了操作于容器类数据的通用算法。

qFind(),qCopy(), qFill(), qSort()等。


类容器类

与容器类有许多共性的三个类是:QString, QByteArray, QVariant

QString的值是16Unicode值,包含ASCIILatin-1QString可认为是一个元素为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::fromAscii(str)qstr= QString::fromLatin1();

QString转变为constchar*型的步骤如下:

  1. 先使用toAscii()toLatin1()返回一个QByteArray类型的对象

  2. 使用QByteArray::data()QByteArray::constData()将其转换为constchar*型。

QString与中文显示问题

QString本身是支持中文显示的,它默认是支持unicode的。要使QString能正常地显示中文,必须传递合适的unicode。有两种方法:

  1. 利用QTextCodectoUnicode()方法。

如: w.setWindowTitle(QTextCodec::codecForName("gb2312")->toUnicode("这是一个测试!"));

  1. 利用QTextCodec的静态方法,如setCodecForCStrings等。

QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"));

优先选择第二种方法。

相关内容