《Qt MOOC系列教程》第一章第三節:容器
1. Qt容器
Qt庫提供了一組通用的基於模板的容器類。這些類可用於儲存指定型別的項。例如,如果您需要一個可調整大小的QString陣列可以使用QVector<QString>
。
這些容器類的設計比STL容器更輕,更安全,更易於使用。如果您不熟悉STL,或者更喜歡以“Qt方式”進行操作,則可以使用這些類而不是STL類。不過也可以使用標準容器。
Qt容器類是隱式共享的,它們是可重入的,並且它們針對速度,低記憶體消耗和最小的內聯程式碼擴充套件進行了優化,從而可以生成較小的可執行檔案。此外,在所有用於訪問它們的執行緒將它們用作只讀容器的情況下,它們是執行緒安全的。
要遍歷儲存在容器中的專案,可以使用兩種型別的迭代器:Java樣式的迭代器和STL樣式的迭代器。Java樣式的迭代器更易於使用並提供高階功能,而STL樣式的迭代器效率更高,可以與Qt和STL的通用演算法一起使用。
Qt還提供了一個foreach
關鍵字,使訪問容器中儲存的所有專案變得非常容易。
2. 容器類
Qt提供了以下順序容器:QList
,QLinkedList
,QVector
,QStack
和QQueue
。對於大多數應用程式,QVector
是最佳的使用型別,除非您對其他型別有特定的需求。
Qt還提供了一些關聯容器:QMap
,QMultiMap
,QHash
,QMultiHash
和QSet
。"Multi"容器可以很方便地支援單個鍵關聯多個值。"Hash"容器通過使用雜湊函式而不是對排序集進行二進位制搜尋來提供更快的查詢。
在特殊情況下,QCache
和QContiguousCache
類提供了對有限快取儲存中的物件的高效雜湊查詢。
容器可以巢狀。例如,完全可以使用QMap<QString, QList<int>>
,其中鍵型別是QString
,值型別是QList<int>
。
容器被定義在與容器同名的標頭檔案中(例如<QLinkedList>
)。為了方便起見,在<QtContainerFwd>
中前置宣告容器。
儲存在各種容器中的值可以是任何可賦值的資料型別。為了具有此資格,型別必須提供預設建構函式、複製建構函式和賦值操作符。這涵蓋了您可能想要儲存在容器中的大多數資料型別,包括基本型別,如int和double、指標型別和Qt資料型別,如QString
、QDate
和QTime
,但不包括QObject
和QObject
子類(QWidget
、QDialog
、QTimer
等)。如果嘗試例項化QList<QWidget>
,編譯器將會抱怨QWidget
的複製建構函式和賦值操作符被禁用。如果要將此類物件儲存在容器中,請將它們儲存為指標,例如作為QList<QWidget *>
。
下面是一個滿足可賦值的資料型別要求的自定義資料型別示例:
class Employee
{
public:
Employee() {}
Employee(const Employee &other);
Employee &operator=(const Employee &other);
private:
QString myName;
QDate myDateOfBirth;
};
如果我們不提供複製建構函式或賦值操作符,C++會提供一個預設實現,執行成員的逐個複製。在上面的例子中,這就足夠了。另外,如果您沒有提供任何建構函式,C++提供了一個預設建構函式,它使用預設建構函式初始化它的成員。雖然它沒有提供任何顯式建構函式或賦值操作符,但以下資料型別可以儲存在容器中:
struct Movie
{
int id;
QString title;
QDate releaseDate;
};
有些容器對它們可以儲存的資料型別有額外的要求。例如,QMap<Key, T>
的Key
型別必須提供operator<()
。這些特殊要求記錄在類的詳細描述中。在某些情況下,特定的功能有特殊的要求,這些是按每個函式描述的。如果沒有滿足要求,編譯器會報錯。
Qt的容器提供了operator<<()
,operator>>()
操作符,因此可以使用QDataStream
輕鬆地對它們進行讀寫。這意味著儲存在容器中的資料型別還必須支援operator<<()
和operator>>()
。提供這種支援很簡單,下面我們如何對上面的Movie結構執行此操作:
QDataStream &operator<<(QDataStream &out, const Movie &movie)
{
out << (quint32)movie.id << movie.title
<< movie.releaseDate;
return out;
}
QDataStream &operator>>(QDataStream &in, Movie &movie)
{
quint32 id;
QDate date;
in >> id >> movie.title >> date;
movie.id = (int)id;
movie.releaseDate = date;
return in;
}
某些容器類函式的文件引用預設構造的值,例如QVector
自動用預設構造的值初始化它的項,如果指定的key不在map中,QMap::value()
返回一個預設構造的值。對於大多數值型別,這僅意味著使用預設建構函式建立一個值(例如的空字串QString
)。但是對於如int
和double
這些原始型別以及指標型別,C++語言未指定任何初始化,在這種情況下,Qt的容器會自動將該值初始化為0。
3. 正確且有效的使用迭代器
迭代器提供了一種統一的方法來訪問容器中的專案。Qt的容器類提供了兩種型別的迭代器:Java樣式的迭代器和STL樣式的迭代器。
對於不可變數的迭代可以通過一個簡單的範圍迴圈來完成for (const ¬eConstRefToMyItem : container)
。
Qt4中引入了Java風格的迭代器。在某些方面,它們比使用STL風格的迭代器更方便,但效率稍低。它們的API模仿Java的迭代器類。
一般來說,我們不建議使用普通Java風格的迭代器,但如果您願意,也可以這樣做。對於可變迭代,Java風格的可變迭代器可以說是最容易使用的:
QMutableListIterator
的示例如下:
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() % 2 != 0)
i.remove();
}
該程式碼從列表中刪除所有奇數。
next()
函式會在每次迴圈中呼叫。它會跳到列表中的下一項。該remove()
函式刪除了我們從列表中跳到的最後一項。呼叫remove()
不會使迭代器無效,因此可以安全地繼續使用它。
如果我們只想修改現有專案的值,則可以使用setValue()
。在下面的程式碼中,我們將大於128的值都替換為128:
QMutableListIterator<int> i(list);
while (i.hasNext()) {
if (i.next() > 128)
i.setValue(128);
}
關聯容器的迭代器的工作方式略有不同,但思想是相同的。官方文件深入介紹了不同的迭代器,還包括多個示例。
在本練習中,您將熟悉QVector
和QMap
,練習說明可以在containers.cpp
中找到。
4. 容器操作中的演算法
如果您有興趣瞭解Qt容器和資料型別的演算法複雜性,請在此處檢視文件。在很多方面,理解為什麼使用某些容器比其他容器更合適是很有用的,在某些應用中甚至關注最有效的增長策略,但在這裡討論這些已經超出了本課程的目標。
獲取更多資訊,請關注作者公眾號:程式設計師練兵場
相關文章
- Qt Creator系列教程QT
- Qt快速入門系列教程目錄QT
- 2017 Material design 第一章第三節《Material特性》Material Design
- Docker框架的使用系列教程(四)容器的使用Docker框架
- Spring系列第三講 Spring容器基本使用及原理Spring
- QT5容器遍歷QT
- Qt Phonon教程QT
- Docker框架使用系列教程(五)容器間的連結Docker框架
- 第三話 初探容器
- JAVA入門第三季第一章第九節課後練習題!Java
- QT小小細節注意點QT
- 《進擊吧!Blazor!》系列入門教程 第一章 8.部署Blazor
- 《進擊吧!Blazor!》系列入門教程 第一章 6.安全Blazor
- Nginx 容器教程Nginx
- 《進擊吧!Blazor!》系列入門教程 第一章 7.圖表Blazor
- Qt QTreeView 常見節點操作QTView
- 檔案目錄(MOOC)
- [Android] Qt安卓教程(2):移植Qt到安卓AndroidQT安卓
- 女裝教程 第一章
- Qt foreach關鍵字遍歷容器QT
- Qt容器類QList、QLinkedList和QVector類QT
- C++ Qt開發:字串QString容器C++QT字串
- 第三節 使用Docker映象Docker
- 第三節,分支結構
- ETL工具-nifi乾貨系列 第三講 nifi web ui 使用教程NifiWebUI
- NDK開發系列第一章
- QT之qss教程-QSpinBoxQT
- 資料庫之淚第一章節資料庫
- Java 容器系列總結Java
- 【Docker】第三篇 Docker容器管理Docker
- C++ Qt開發:使用順序容器類C++QT
- C++ Qt開發:使用關聯容器類C++QT
- Flask教程第一章:Hello,World!Flask
- webpack4 系列教程(十二):處理第三方JavaScript庫WebJavaScript
- 2021前端學習筆記-第一章第三節-opacity_visibility_display優劣前端筆記
- 程式設計實習MOOC/7998/3w8:第三週程式填空題3程式設計
- 程式設計實習MOOC/7997/3w7:第三週程式填空題2程式設計
- [Android] Qt安卓教程(1): 從Qt5.1開始AndroidQT安卓