Qt系列文章之十(Qt 數據類型介紹以及迭代器使用下)

2021-12-22 頭號公社

5. QMultiHash
  QMultiHashQHash的子類,是用於處理多值映射的便利類,其用法與QMultiMap類似。

迭代器

  終於將容器給講解的差不多了,可以來到我們的重點——講解 迭代器 的使用

  迭代器(iterator) 為訪問容器類裡的數據項提供了統一的方法,Qt 有兩種迭代器類: Java 類型的迭代器和STL類型的迭代器。

  Java類型 的迭代器更易於使用,且提供一些高級功能,而STL類型的迭代器效率更高。

  Qt 還提供一個關鍵字 foreach() (實際是 <QtGlobal\> 裡定義的一個宏) 用於方便地訪問容器裡所有數據項。

Java類型迭代器Java類型迭代器集合總覽

  java風格的迭代器是Qt 4中的新元素,是Qt應用程式中使用的標準迭代器。它們使用起來比STL風格的迭代器更方便,但效率稍低一些。它們的API模仿Java的迭代器類

  對於每個容器類 ,有兩個Java類型迭代器:一個用於只讀操作,一個用於讀寫操作,各個Java類型 的容器類見下表.

容器類只讀迭代器讀寫迭代器QList<T\>, QQueue<T\>QListIterator<T\>QMutableListIterator<T\>QLinkedList<T\>QLinkedListIterator<T\>QMutableLinkedListIterator<T\>QVector<T\>, QStack <T\>QVectorIterator<T\>QMutableVectorIterator<T\>QSet<T\>QSetIterator<T\>QMutableSetIterator<T\>QMap, QMultiMapQMapIteratorQMutableMapIteratorQHash, QMultiHashQHashIteratorQMutableHashIterator

  QMapQHash等關聯容器類的迭代器用法相同,QListQLinkedListQSet等容器類的用法相同,所以下面只以QMapQList為例介紹迭代器的用法

Java類型有序容器類的迭代器的使用

  Java類型迭代器的指針不是指向一個數據項,而是在數據項之間,迭代器指針位置示意圖如下圖所示。

在這裡插入圖片描述
  下面是遍歷訪問一個 QList<QString\> 容器的所有數據項的典型代碼。

QList<QString> list;
list << "A" << "B" << "C" << "D";

QListIterator<QString> i(list);

while (i.hasNext())
    qDebug() << i.next();

  QList<QString\> 容器對象list作為參數傳遞給 QListIterator< QString > 迭代器i 的構造函數,i 用於對 list 作只讀遍歷。起始時刻,迭代器指針在容器第一個數據項的前面(上圖中 數據項A 的前面),調用 hasNext() 判斷在迭代器指針後面是否還有數據項,如果有,就調用 next() 跳過一個數據項,並且 next() 函數返回跳過去的那個數據項。

  也可以反向遍歷,示例代碼如下:

QListIterator<QString> i (list) ;
i.toBack();
while (i.hasPrevious())
    qDebug() << i.previous () ;

  該代碼與前向迭代是對稱的,除了我們首先調用toBack()將迭代器移動到列表中最後一項之後。

  下面的圖表說明了在迭代器上調用 next()previous() 的效果:

在這裡插入圖片描述

  QListIterator 用於移動指針和讀取數據的函數見下表:

函數名功能描述void toFront()迭代器移動到列表的最前面(第一個數據項之前)void toBack()迭代器移動到列表的最後面(最後一個數據項之後)bool hasNext()如果迭代器不是位於列表最後位置,返回trueconst T & next()返回下一個數據項,並且迭代器後移-一個位置const T & peekNext()返回下一個數據項,但是不移動迭代器位置bool hasPrevious()如果迭代器不是位於列表的最前面,返回trueconst T & previous()返回前一個數據項,並且迭代器前移-一個位置const T & peekPrevious()返回前一個數據項,但是不移動迭代器指針

  QListIterator是只讀訪問容器內數據項的迭代器,若要在遍歷過程中對容器的數據進行修改,需要使用QMutableListIterator。例如下面的示例代碼為刪除容器中數據為奇數的項。

QList<int> list;
list <<1 <<2<<3<<4<<5;

QMutableListIterator<int> i(list);
while (i.hasNext()){
    if(i.next()%2 != 0)
        i. remove();
}

  remove() 函數移除next)函數剛剛跳過的一一個 數據項,不會使迭代器失效。setValue() 函數可以修改剛剛跳過去的數據項的值。

Java類型關聯容器類的迭代器的使用

  對於關聯容器類QMap<Key T\>,使用QMapIteratorQMutableMapIterator迭代器類,它們具有前面表中所示的所有函數,主要是增加了 key()和value() 函數用於獲取剛剛跳過的數據項的鍵和值。
  例如,下面的代碼將刪除鍵(城市名稱)裡以City結尾的數據項。

QMap<QString,QString> map;
map.insert("Paris", "France");
map.insert("New York", "USA");
map.insert("Mexico City", "USA");
map.insert("Moscow", "Russia");

QMutableMapIterator<QString, QString> i(map);

while (i.hasNext()){
    if (i.next().key().endsWith("City"))
        i.remove() ;
}

  如果是在多值容器裡遍歷,可以用findNext()或findPrevious()查找下一個或上一個值,如下面的代碼將刪除上一示例代碼中 map 裡值為 USA 的所有數據項。

QMutableMapIterator<QString, QString>  i(map);

while (i.findNext("USA"))
    i.remove();

STL類型迭代器STL類型迭代器集合總覽

  STL風格的迭代器在Qt 2.0發布後就可用了。它們與Qt和STL的通用算法兼容,並針對速度進行了優化

  對於每一個容器類,都有兩個STL類型迭代器: 一個用於只讀訪問,一個用於讀寫訪問。無需修改數據時一定使用只讀迭代器,因為它們速度更快。具體類型見下表:

容器類只讀迭代器讀寫迭代器QList<T\>, QQueue<T\>QList<T\>::const_iteratorQList<T\>::iteratorQLinkedList<T\>QLinkedList<T\> :const_iteratorQLinkedList<T\>::iteratorQVector<T\>, QStack<T\>QVector<T\>::const_iteratorQVector<T\> :iteratorQSet<T\>QSet<T\>::const_iteratorQSet<T\>::iteratorQMap,QMultiMapQMap:const_iteratorQMap::iteratorQHash,QMultiHashQHash::const_iteratorQHash::iterator

注意:在定義只讀迭代器和讀寫迭代器時的區別, 它們使用了不同的關鍵字,const_iterator 定義只讀迭代器,iterator定義讀寫迭代器。此外,還可以使用const_reverse_iteratorreverse_iterator 定義相應的反向迭代器。

  STL類型 的迭代器是數組的指針,所以 ++ 運算符使迭代器指向下一個數據項,* 運算符返回數據項內容。與Java類型 的迭代器不同,STL 迭代器 直接指向數據項,STL 迭代器指向位置示意圖如下圖所示。

在這裡插入圖片描述

  begin() 函數使迭代器指向容器的第一個數據項,end() 函數使迭代器指向一個虛擬的表示結尾的數據項,end() 表示的數據項是無效的,一般用作循環結束條件。
  下面仍然以QList和QMap為例說明STL迭代器的用法,其他容器類迭代器的用法類似。

STL有序容器類的迭代器用法

  下面的示例代碼將QList<QString\>  list 裡的數據項逐項輸出。

  iterator 用法

 QList<QString> list;
 list << "A" << "B" << "C" << "D";

 QList<QString>::iterator i;
 for (i = list.begin(); i != list.end(); ++i)
     *i = (*i).toLower();

  const_iterator 用法

QList<QString> list;
list << "A" << "B" <<"C" << "D";
QList<QString>::const_iterator i;
for (i = list.constBegin() ; i != list.constEnd(); ++i)
    qDebug() << *i;

  constBegin()和constEnd() 是用於只讀迭代器的,表示起始和結束位置。若使用反向讀寫迭代器,並將上面示例代碼中list 的數據項都改為小寫,代碼如下:

QList<QString>::reverse_iterator i;

for (i = list.rbegin(); i != list.rend(); ++i)
{
    *i = i->toLower () ;
}

STL關聯容器類的迭代器的用法

  對於關聯容器類QMapQHash,迭代器的 * 操作符返回數據項的值。如果想返回鍵,使用key() 函數。對應的,用 value() 函數返回一個項的值。
  例如,下面的代碼將QMapmap中所有項的鍵和值輸出:

QMap<int,int> map;
QMap<int,int>::const_iterator i;

for (i = map.constBegin() ; i != map.constEnd() ; ++i)
    qDebug() << i.key() << ":"<< i.value();

Qt的隱式共享

  QtAPI包含很多返回值為QListQStringList的函數,要遍歷這些返回的容器,必須先複製。由於Qt使用了隱式共享,這樣的複製並無多大開銷。例如下面的代碼是正確的。

const QList<int> sizes = splitter->sizes() ;

QList<int>::const_iterator i;
for (i = sizes.begin(); i != sizes.end(); ++i)
    ...

  隱式共享 ( Implicit Sharing) 是對象的管理方法。一個對象被隱式共享,只是傳遞該對象的一個指針給使用者,而不實際複製對象數據,只有在使用者修改數據時,才實質複製共享對象給使用者。如在上面的代碼中,splitter->sizes()返回的是一個QList<int\>列表對象sizes, 但是實際上代碼並不將splitter->sizes()表示的列表內容完全複製給變量sizes,只是傳遞給它一個指針。只有當sizes 發生數據修改時,才會將共享對象的數據複製給sizes,這樣避免了不必要的複製,減少了資源佔用。

  而下面的代碼是錯誤的。

QList<int>::const_iterator i;

for (i = splitter->sizes().begin(); i != splitter->sizes().end(); ++i)
    ...

  對於STL類型的迭代器,隱式共享還涉及另外一個問題,即當有- -個迭代器在操作- - 個容器變量時,不要去複製這個容器變量。

foreach關鍵字

  目前foreach已經可以被C++11 標準庫for循環代替了。所以代碼實用時不建議使用foreach,直接使用for即可,下面還是介紹下foreach的大概用法

  如果只是想遍歷容器中所有的項,可以使用 foreach 關鍵字。foreach 是<QtGlobal\>頭文件中定義的一個宏。使用foreach的句法是:

foreach(variable,container )

  使用foreach的代碼比使用迭代器更簡潔。例如,使用foreach 遍歷一個QStringList的示例代碼如下:

QStringList list;
list<<"A"<<"B"<<"C";

QString str;
foreach (str, list)
    qDebug() < str;

替代的C++11for循環用法,(僅限C++11)
for(str:list)
    qDebug() < str;

輸出結果:A,B,C

  用於迭代的變量也可以在foreach語句裡定義,foreach 語句也可以使用花括號,可以使用break 退出迭代,示例代碼如下:

QStringList strlist;
strlist<<"A"<<"B"<<"C";

foreach (const QString &str, strlist) {
if (str. isEmpty())
    break;

qDebug() << str;
}

  對於QMapQHashforeach 會自動訪問 鍵一一值 對裡的值,所以無需調用values()。 如果需要訪問鍵則可以調用keys() ,示例代碼如下:

QMap<QString,int> map;

foreach (const QString &str, map.keys() )
    qDebug() << str << ":" << map.value(str) ;

注意: foreach 關鍵字遍歷一個容器變量是創建了容器的一個副本,所以不能修改原來容器變量的數據項。

到這裡,容器,迭代器的使用就全部講解完畢了!又不懂得隨時評論留言!

Qt/Qml零基礎入門系列文章總綱

相關焦點

  • 新購買的imx6ull開發板如何使用:下載qt程序,進入Linux命令行系統
    大家好,這裡是義縣遊學電子科技.今天帶給您的是如何使用新購買的imx6ull開發板.新購買的開發板上電後會直接進入原子的演示程序,那如何才能顯示我們自己編譯好的qt程序呢.如何進入Linux命令行終端呢?這就是我們今天的主題了.
  • qt creator連接資料庫並實現用戶登錄和註冊相關的開發源碼詳解
    項目最終實現效果圖具體代碼詳解1 如何給qt界面設置相關的圖片呢?首先我們新建一個基於對話框的程序,名字自己定義即可。2 如何連接相關的資料庫,進行資料庫相關的調用關聯資料庫最重要的就是調用mysql進行相關的用戶註冊信息的記錄,我們為何要使用sql呢?是因為我們每次進行註冊的時候,都要進行相關的數據信息的登錄,從使用和存儲的性價比來看,資料庫是最好的選擇。
  • Python進階:迭代器與迭代器切片
    在前兩篇關於 Python 切片的文章中,我們學習了切片的基礎用法、高級用法、使用誤區,以及自定義對象如何實現切片用法(相關連結見文末)。本文是切片系列的第三篇,主要內容是迭代器切片。迭代器是 Python 中獨特的一種高級特性,而切片也是一種高級特性,兩者相結合,會產生什麼樣的結果呢?
  • Qt 模塊簡介
    在《UI 文件設計與運行機制》一文中,介紹了 Qt 類庫是以模塊的形式組織各種功能的類,根據項目涉及的功能需求,在項目中添加適當的類庫模塊支持
  • Python 迭代器和 C++ 迭代器,最大的不同竟然是……
    本文將基於 C++ 與 Python,深入討論這一系列問題。什麼是迭代器?我們為什麼要使用迭代器?什麼是迭代器?在很多討論 Python 迭代器的書籍與文章中,我看到這樣兩種觀點:1. 迭代器是為了節約數據結構所產生的內存;2. 遍歷迭代器效率更高。
  • qt5.15.2在Ubuntu系統安裝完成後無法啟動qtcreator的解決方法
    1.qtcreator中沒有c++編譯器,需要使用命令:sudo apt install build-essential重新打開qt creator即可自動識別安裝的編譯器了.這個命令將安裝一堆新包,包括
  • Qt 6.0 發布首個預覽版本 - OSCHINA - 中文開源技術交流社區
    Qt 6.0 需要 C++ 17 支持,如果要使用較舊的編譯器,還是選用 Qt 5.15 比較好。Qt GUI Qt Widgets Qt Network Qt QML Qt Quick Qt Quick Controls Qt SVG Qt Network Authorization Qt SQL Qt Test 以及其他
  • Le Creuset 酷彩 琺瑯鋼深燉鍋 N4100 馬賽藍 6qt 799元包郵包稅
    Le Creuset 酷彩 琺瑯鋼深燉鍋 N4100 馬賽藍 6qt 799元包郵包稅 2016年11月25日 08:29作者:價格網編輯:網絡
  • Qt程序打包三部曲,從應用程式到安裝包
    Qt程序打包三部曲,從應用程式到安裝包 本章節主要是講解下如何打包Qt程序。Qt使用自帶的windeployqt 處理依賴庫生成exe來發布軟體。Qt使用自帶的windeployqt 處理依賴庫生成exe來發布軟體。準備exe1.程序要想發布,在編譯器編譯一定要選擇「release」而不是「debug」,編譯成release版本
  • Python——迭代器的幾個高級用法
    當我們知道頭部不符合情況的數據的格式的時候,可以使用dropwhile來規定過濾的格式。如果我們 知道需要過濾的條數 ,則可以使用另外一個工具,叫做islice,它的本質是一個切片函數,就像是Python當中數組的切片功能一樣,可以切出迭代器當中指定片段的數據。
  • OpenGL_Qt學習筆記之_05(紋理映射)
    在上一篇文章OpenGL_Qt學習筆記之_04(3D圖形的繪製和旋轉)中,我們繪製的空間體的表面都是一些光滑的顏色,如果要在其表面採用那種方法繪製圖像的話,則必須利用微分的思想,一個一個的繪製小圖像,然後拼接起來,可想而知,這個過程是多麼的複雜,opengl的紋理映射就可以很好的解決這一問題。
  • Python中可迭代對象、迭代器以及iter函數的兩個用法詳解
    這些數據結構之所以能稱之為Iterable,是因為其內部實現了__iter__()方法,從而可迭代。其中__next__方法用於產出下一個元素。 由繼承圖可見,迭代器一定是可迭代對象,可迭代對象不一定是迭代器 迭代器有兩個基本的方法:iter() 和 next()。
  • 一文解開可迭代對象和迭代器的神秘面紗
    1.迭代器(Iterator)迭代器表示的是一個數據流,並不表示一個數據實體,我們可以使用next()方法計算下一個數據。或者說,可以使用next()方法的就是迭代器。生成器是迭代器,生成器可以使用下面這種方式生成。
  • 類似Qt 的「跨平臺 GUI 框架 GOSP」時隔一年有重大更新
    100%使用圖片來實現個性化的控制項和界面。(見下文的截圖) 提供了類似Qt的API,可提供基於qt creator的集成開發環境。 基於別具一格的Giveda信號槽技術,各個模塊代碼之間無耦合。 無耦合的代碼,史上最容易復用,沒有之一。
  • 一篇文章掌握 Python 內置 zip() 的全部內容
    zip() 是 Python 中最好用的內置類型之一,它可以接收多個可迭代對象參數,再返回一個迭代器,可以把不同可迭代對象的元素組合起來。我之前寫迭代器系列的時候,在《Python進階:設計模式之迭代器模式》中簡單地介紹過它,前幾天翻譯了 Python 3.10 採納的 PEP-618 ,介紹了它將會迎來的變更。
  • 《前端5分鐘》之迭代器模式的N+1種應用場景
    1.迭代器的含義迭代器模式主要的思想就是在不暴露對象內部結構的同時可以按照一定順序訪問對象內部的元素。], (index, value) => { console.log(index, value) })3.實現一個對象迭代器對象迭代器和數組迭代器類似, 只是傳參不同,如下:// 對象迭代器let eachObj
  • 四種高性能數據類型,Python collections助你優化代碼、簡潔任務
    在這篇文章中,機器學習工程師 George Seif 介紹了 Python collections 模塊最受歡迎的四種數據類型以及它們各自的使用方法。這些數據類型可以對代碼進行優化,進而實現更簡潔的任務執行。Python 的最大優勢之一就是它有各種各樣的模塊和軟體包可供選擇。這些模塊和包將 Python 的功能擴展到了許多流行領域,包括機器學習、數據科學、Web 開發和前端等。
  • python中常見的對象辨析(可迭代對象、迭代器對象、生成器對象)
    一 可迭代對象IterableA.定義可作用於for循環的對象叫可迭代對象B.包括1.集合數據類型 序列,字典,集合2.迭代器對象C.訪問可迭代對象1.集合數據類型使用各自的訪問方法2.迭代器對象使用迭代器對象訪問的方法D.注意1.具有
  • 設計模式之迭代器模式(Java實現)
    設計模式之迭代器模式(Java實現)迭代器模式(Iterator Pattern) :它提供一種方式訪問一個容器對象的各個元素,而又不需暴露該對象的內部細節迭代器模式是為了解決遍歷容器中的元素而產生的。先看看下面的通用類圖:
  • 第20篇 Qt5之2D繪圖(十)圖形視圖框架(下)
    QGraphicsScene中提供了兩種選擇,它們在一個枚舉類型QGraphicsScene::ItemIndexMethod中,分別是:        我們可以使用setItemIndexMethod()函數進行索引算法的更改。