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::fromAscii(str)或qstr= QString::fromLatin1();
將QString轉變為constchar*型的步驟如下:
先使用toAscii()或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"));
優先選擇第二種方法。