1、Qt的元对象系统
Qt的元对象提供
对象间通信的信号和槽机制、运行时类型信息和动态属性系统。
QT RTTI 运行时类型识别技术(运行时类型信息
)
除了C++为我们提供的两种RTTI运算符(
dynamic_cast 和 typeid)外,qt也为我们提供了两种运行时类型识别机制:
(1)
qobject_cast
(2)
Qobject::inherits()
QT对象间的交流(槽函数)
QObject::connect()函数的原型是 [static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
参数Qt::ConnectionType type 就是Qt中信号与槽的连接方式。
默认连接:也称为AutoConnection,根据信号和槽所在的对象是否在
同一线程来决定连接方式。如果
信号和槽在同一线程,则使用DirectConnection;如果
信号和槽在不同线程,则使用
QueuedConnection。
直连(DirectConnection),信号在哪,就在哪个线程执行。这种连接方式
最好只在同一线程中使用。
队列连接(QueuedConnection),无论信号和槽在同一线程还是不同线程,
槽函数不会立刻执行,等到接受者的
当前执行的函数执行完才会执行槽函数。这种连接方式中,槽函数不会立刻执行,
会等待接收对象的当前线程完成当前的任务后,在事件循环中执行。
阻塞队列连接(BlockingQueuedConnection),这种连接方式与队列连接类似,槽函数调用时机相同,只是会在
发送者所在的线程会阻塞,直到槽函数运行完,发送者和接受者绝对不能在同一个线程。
唯一连接:(Qt::UniqueConnect),
一个信号只能有一个槽连接,多个会失败。
可以使用|与以上四种结合使用。
优点:
类型安全:信号和槽的签名必须是等同的,即信号的参数类型和参数个数必须与接收该信号的槽的参数类型和参数个数相同(
信号参数数大于等于槽的参数)。
松散耦合:
信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无须知道是哪个对象的哪个槽需要接收它发出的信号,而对象的槽也不知道是哪些信号关联了自己。这样,一个对象可以在不等待接收者的响应下继续执行,提高了程序的响应性能。
即使关联的对象在运行时被删除,应用程序也不会崩溃。
异步通信:信号和槽机制可以实现异步通信,
一个对象可以在不等待接收者的响应下继续执行,提高了程序的响应性能。
事件驱动:在Qt中的图形界面编程常常与事件处理有关。信号与槽机制使得处理事件变得更加方便,能够
轻松地处理按钮点击、鼠标事件等。
缺点:
速度较慢。与回调函数相比
,信号和槽机制运行速度比直接调用非虚函数慢
10倍。
原因:1、需要定位接收对象的信号(
找到对象位置)。2、安全地遍历所有关联槽(
一个对象有多个槽,需要一个一个对比)
3、编组解组
传递参数 4、
多线程的时候,信号需要排队等待。(然而,与创建对象的new操作及删除对象的delete操作相比,信号和槽的运行代价只是他们很少的一部分。信号和槽机制导致的这点性能损耗,对实时应用程序是可以忽略的。)
动态属性:动态使用属性,可以随时删除和增加属性
在Qt中我们可以使用宏
Q_PROPERTY()宏来实现。一个属性可以使用常规函数
QObject::property()和QObject::setProperty()进行读写
通过
使用Q_PROPERTY宏,我们可以在运行时动态地添加或删除属性,这为我们提供了更大的灵活性和便利性。
// 中括号中的内容为可选项
Q_PROPERTY(
type name //属性的类型 名字
(READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction |WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal] //通知的信号名
[REVISION int] //版本号
[DESIGNABLE bool] //当前该属性可不可以在设计模式设置
[SCRIPTABLE bool] //可以不可以被脚本访问
[STORED bool] //属性值是否存储
[USER bool] //是否提供给用户编辑权限
[CONSTANT] //常量
[FINAL] //不能被重写
)
1. type name
属性类型可以是
QVariant支持的任何类型,也可以是用户定义的类型;
2. READ 和 MEMBER
如果没有MEMBER,则必须要有READ。
READ 后面定义获取属性值的函数,该函数是const;
WRITE 设置属性值,是可选的;
MEMBER 如果一个属性不需要 READ ,但又想使用属性系统,可以使用MEMBER来注册,MEMBER后面是成员变量的名字;
3. RESET
可选,将属性设置为默认值,该RESET函数必须返回void并且不带参数。
4. NOTIFY
可选,NOTIFY 后面跟该类中已经定义的一个信号函数,只要该属性的值发生更改,就会发出该信号。这个信号函数必须采用零个或一个参数,
该参数必须与属性的类型相同。
5. REVISION int
可选,版本信息(通常用于QML)。
6. DESIGNABLE bool
可选,表示属性是否能在GUI设计工具的属性编辑器中可见(例如,Qt Designer)。大多数属性是DESIGNABLE(默认为true)。
7. SCRIPTABLE bool
可选,SCRIPTABLE属性表示脚本引擎是否应该可以访问此属性(默认为true)
8. STORED bool
可选,该属性是单独存在还是从其他值中获取的。大部分是true,一个反例是QWidget::minimumWidth()的值从QWidget::minimumSize()中获取,因此它的STORED为false。
9. USER bool
可选,表示是否可以被用户所编辑。
10. CONSTANT
可选,CONSTANT表明属性值是常量,不可更改,因此不能有WRITE方法或NOTIFY信号。对于给定的对象实例,常量属性的READ方法每次调用时都必须返回相同的值。
对于对象的不同实例,该常数值可以是不同的。
11. FINAL
可选,FINAL表示属性不会被派生类覆盖,在某些情况下,这可用于性能优化。
示例演示
定义多个动态属性
添加动态属性,并将属性添加到元对象系统,让它成为类的一员
删除动态属性,
使用removeProperty函数将其从元对象中删除
2、
对象模型
一、描述
1、QObject类是所有Qt对象的基类。
2、
QObject是Qt对象模型的核心。该模型的核心特性是一种非常强大的无缝对象通信机制,称为信号和槽。可以使用connect()将信号连接到槽,
并使用disconnect()销毁连接。为了避免永无止境的通知循环,可以使用blockSignals()临时阻止信号。而connectNotify()和disconnectNotify()
使跟踪连接成为可能。
3、
对象通过对象树的形式组织。当
创建一个以另一个对象为父对象的QObject时,该对象将自动将自己添加到父对象的children()列表中。
父对象
拥有对象的所有权,父对象将在析构函数中自动删除它的子对象。可以使用
findChild()或findChildren()查找对象的子对象。
4、每个对象都有一个objectName()。其类名可以通过相应的metaObject()找到。可以使用inherits()函数确定对象的类是否继承QObject继承层
次结构中的另一个类。
5、当一个对象被删除时,它会发出一个destroyed()信号。
6、QObjects可以通过event()接收事件并过滤其他对象的事件。可以重新实现方便的处理程序childEvent(),以捕获子事件。
7、QObject在Qt中提供了基本的计时器支持。
8、对于实现信号、槽或属性的任何对象,Q_OBJECT 宏都是必需的。还需要
在源文件上运行元对象编译器(MOC)。
强烈建议在QObject的所有
子类中
使用此宏,不管它们是否实际使用信号、槽和属性,否则可能会导致某些函数表现出奇怪的行为。
9、所有Qt widgets都继承QObject。函数
isWidgeType()返回一个对象是否是一个widget。它比qobject_cast<QWidget *>(obj)或obj->inherits(“QWidget”)
快得多。
二、线程相关
1、当QObject接收到信号或发布的事件时,槽函数或事件处理程序将在对象所在的线程中运行。(如果QObject没有线程关联(即如果thread()返回nullptr),
或者如果它位于没有运行事件循环的线程中,则它无法接收信号或发布的事件)。
这里需要解释一下:QObject说的是对象不能不在同一个线程,而connect的关联对象肯定是在同一个线程,但是对应的信号和槽函数不一定在同一个线程。
2、
默认情况下,
QObject存在于创建它的线程中
。可以使用thread()查询对象的线程关联,并使用
moveToThread()更改对象的线程关联
。
3、所有QObject必须与其父对象位于同一线程中。因此:
如果所涉及的两个QObject位于不同的线程中,setParent()将失败。
当
一个QObject对象被移动到另一个线程
时,该
对象的所有子线程也将被自动移动
。//这样就显得比较高级了
如果
QObject对象有父对象,moveToThread()将失败
。//只有先移动父对象,才能移动子对象
如果
QObject对象是在QThread::run()中创建的
,则
它们不能成为QThread对象的子对象,因为QThread对象不在调用QThread::run()的线程中。
注意:
QObject的成员变量不会自动成为其子变量
。必须通过向
子构造函数传递指针或调用setParent()来设置父子关系
。如果
没有此步骤
,调用moveToThread()时,
对象的成员变量将
保留在旧线程
中。
三、无复制构造函数和赋值运算符
QObject既没有复制构造函数,也没有赋值运算符
。它们是在宏
Q_DISABLE_COPY()中设置了禁止生成
。实际上,所有从QObject派生的Qt类
(直接或间接)都使用这个宏来
声明它们的复制构造函数和赋值操作符是私有的
。
这带来的结果是应该使用
指向QObject(或者指向自定义的QObject子类)的指针
。例如,
如果没有复制构造函数
,就
不能使用QObject的子类
作为存储在某个容器类中的值,必须存储指针。
四、自动连接(ui文件)
Qt的元对象系统
提供了一种机制来自动连接QObject子类及其子类之间的信号和槽
。只要用合适的对象名定义对象,并且槽遵循简单的命名约定,
就可以在运行时通过
QMetaObject::connectSlotsByName()
函数执行此连接。
uic(用户界面编译器)生成调用此函数的代码,以便在使用Qt Designer创建的窗体上的小部件之间执行自动连接。
3、
对象数树
在Qt中,
对象树是一种组织和管理QObject类及其子类对象的方式
。当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),
那么这个QObject就会被添加到父对象的children()列表中。这样,当父对象被销毁时,这个QObject也会被销毁。
对象树中的析构顺序与构造顺序相反。
在对象树中,当父对象析构时,其children()列表中的所有对象也会被析构。例如,
当关闭一个窗口时
,该窗口内的组件对象也会被销毁,这就是对象树的作用。
STL在qt当中用法详解
Qt常用的容器一一详解
简单描述以及应用场景
QList<T>:
动态数组,
支持快速的数据访问和插入,适合使用
类似于向量的算法(优化过的vector)。
存储原理:
对于int、char,QString等基础类型,它是
直接存储引用,对于Class、Struct sizeof(T)<=sizeof(void*)等类型,它是
存储对象指针。
窗口列表
只能指针存储(
避免内存过大
)。
当QList满了之后,它会自动分配一块更大的内存空间,并将原有的元素复制到新的内存空间中,然后释放原来的内存空间。
优缺点---优点
1、
自动内存管理:可以自动调整内部存储空间的容量(当 QList 需要更多空间时,
它会分配一个比当前容量大的新空间。当 QList 中的元素被移除时,
QList 可能会
释放部分空间以节省内存。)
2、
动态数组:QList 是一个动态数组,支持动态扩展和缩小。这使得在进行向量算法时,可以更加灵活地处理数据的数量和大小变化。
3、
简单易用:QList 的 API
接口简洁易用,提供了丰富的方法来操作元素,例如 append()、remove()、contains() 等。这些方法使得在进行向量算法时,
可以更加方便地进行数据的处理和转换。
4、
类型安全:QList 可以存储任意类型的对象引用,类型安全且易于使用。在进行向量算法时,可以更加方便地处理不同类型的数据。
优缺点---缺点
1、
性能问题:由于 QList 是一个动态数组,因此在执行某些性能敏感的向量算法时,可能会比 std::vector 略慢一些。
2、内存开销:由于 QList 实现了自动内存管理,因此在存储大量数据时,可能会比 std::vector 占用
更多的内存开销(这次内存用完,下次分配更多,导致开销)。
代码示例:
vec << 1 << 2 << 3 << 4 << 5;也可以
简单描述以及应用场景
QVector<T>:和 QList<T> 类似的动态数组容器,但是在内存分配和数据访问上相对更加高效。适用于需要大量的读写操作的场景。
存储原理:
QVector会维护一个capacity变量,表示的是QVector的容量大小,即
表示已分配的内存空间大小。如果QVector现有空间已存满元素,
在使用push_back新增数据的时候就会执行扩容操作,分配一块更大的内存,
将原来的数据copy过来,
同时释放之前的内存,再在新的
内存空间中存入新增的元素。QVector将每一个元素存储在相邻的内存位置,并提供快速的基于索引的访问。
优缺点---优点:
1、内存分配机制:
QVector会
自动调整内存大小以适应存储的元素数量变化,这使得它能够
灵活地处理大量数据,并减少了手动管理内存的复杂性。
2、
元素存储方式:
QVector将元素存储在
相邻的内存位置,这使得它
能够快速地通过索引访问元素,同时保持了元素的顺序。访问数据效率高
优缺点---缺点:
1、
在插入和删除元素时,可能需要重新分配内存,导致性能下降。特别是当
QVector存储大量数据时,重新分配内存的操作可能会导致
较长的执行时间。
2、QVector的子类有QPolygon,QPolygonF,QStack,QVulkanInfoVector和QXmlStreamAttributes。虽然这些子类提供了更多的
功能和灵活性,但也增加了使用的复杂性。
代码示例:...
QVector与QList的区别总结
QList和QVector都是Qt框架中的容器类,它们都可以用于存储一系列元素的集合。然而,它们在
内存分配、元素存储方式和性能方面存
在一些差异。选择使用哪个容器类取决于具体的使用场景和需求。
简单描述以及应用场景(用的少就不说了)
QLinkedList<T>:双向链表,支持元素快速插入、删除,以及排序等操作,适合频繁的删除、插入元素的场景。
存储原理:
QLinkedList是一个双向链表实现的List,每个节点上有两个指针(item/prve/next),链表中的每一个元素称之为节点,节点在运行时动态
生成,
存储数据的数据域和存储下一个节点地址的指针域。QLinkedList是
非线程安全的,
允许元素为null,允许重复元素,
基于链表实现的,
因此
插入删除效率高,查找效率低(虽然有一个加速动作),不存在容量不足的问题,所以没有扩容的方法,还实现了栈和队列的操作方法,
因此也可以作为栈、队列和双端队列来使用。
优缺点---优点:
优缺点---缺点:
代码示例
简单描述以及应用场景
QMap<Key, T>:关联数组,支持按键值(Key)进行
快速的数据
访问和查找
(最慢是log2n),
适合需要快速查找和修改元素的场景。
存储原理:QMap是一个以
键值对形式存储数据的容器类,它以
键的升序存储键值对。QMap中的键值对是通过键进行排序的,因此键的类型
必须重载小于操作符(<)以定义键的排序规则。在QMap中,
键值对是存储在一块连续的内存区域中的。每个
键值对由一个键和一个值组成,
它们紧密相邻,并
通过指针链接在一起。每个键值对都被
封装在一个节点中,节点中包含键和值,以及指向下一个节点的指针。当插入一个新
的键值对时,QMap会根据键的排序规则找到应该插入的位置,并创建一个新的节点,将其插入到正确的位置。
如果插入的键已经存在,则更
新对应的值。在QMap中,可以通过键来访问对应的值。
如果给定的键不存在,QMap会返回一个零值(例如,对于数值类型,返回0;对于字
符串类型,返回空字符串)。总之,QMap是一个以升序键顺序存储键值对的容器类,通过重载小于操作符来定义键的排序规则,并使用节点和
指针链接存储键值对。
(红黑树)
优缺点---优点:
1、自动排序:QMap内部实现采用红黑树,因此能够自动对键进行排序。适用于大数据集合或需要按照特定排序方式访问元素的情况。
2、支持高效的查找、插入和删除操作:QMap内部采用红黑树进行存储,因此可以
快速查找、插入和删除元素。
3、提供STL风格的迭代器:QMap提供类似于STL的迭代器,可以通过迭代器访问元素。
4、支持API进行查找操作:QMap提供
lowerBound()和upperBound()等API支持查找操作。
5、内存管理:QMap在删除元素时,内部会自动进行平衡处理,以保
证树的高度不会太高,因此性能较好。
优缺点---缺点:
1、不能保持元素的插入顺序:QMap是以升序键顺序存储键值对的,因此不能保持元素的插入顺序。
2、不支持随机访问:QMap不支持随机访问,只能通过迭代器或API进行顺序访问。
代码示例:
简单描述以及应用场景
QHash<Key, T>:哈希表,具有较快的插入、删除和查找元素的特性,适用于元素数量不固定,且需要快速查找元素的场景。
存储原理:
QHash是Qt框架提供的
哈希表(也称散列表)容器类,它的存储原理是
通过哈希函数将键映射到对应的存储位置上,以
实现高效的查找和插入操作。
QHash的原理可以分为两个主要部分:
哈希函数和散列桶。
哈希函数是QHash的核心组成部分,它负责将输入数据转化为一个唯一的哈希值。QHash使用的哈希函数是一种特殊的算法,通过
对输入数据进行计算,
生成一个固定长度的二进制值作为哈希码。哈希码用于
确定数据在散列桶中的存储位置。
散列桶是QHash用于存储数据的结构。散列桶可以理解为一个数组,数组中的每个元素称为一个
槽位。当输入数据经过哈希函数处理
后,
得到的哈希码对应一个特定的槽位。这个槽位就是数据在QHash中的存储位置。为了实现高效的插入和查找操作,QHash会根据
哈希码的值分布情况动态调整散列桶的大小,以保持散列桶的负载平衡。
优缺点---优点:
1、高效的查找、插入和删除操作。QHash使用哈希表实现,通过哈希函数将键映射到对应的存储位置上,能够快速地查找、插入和删除数据。
2、支持键值对的存储。QHash允许存储键值对,通过键可以方便地获取对应的值。
3、支持自定义的哈希函数和冲突解决策略(解决哈希冲突主要有两个方案:闭散列(
也叫开放定址法,
二次探测和线性探测) 和 开散列(
又叫链地址法)
)
。QHash允许用户提供自定义的哈希函数和冲突解决策略,以满足不同的需求。
优缺点---缺点:
1、
元素排列无序。QHash中的键值对是按照哈希值进行存储的,而不是按照键的顺序排列,因此无法保证元素的顺序性。
2、
不支持随机访问。由于QHash是基于链表的数据结构,因此不支持随机访问,只能从头开始遍历链表来查找特定的元素。
3、
需要提供自定义的哈希函数和冲突解决策略。在使用QHash时,
需要提供合适的哈希函数和冲突解决策略,否则可能会导致性能问题或者出现错误。
代码示例
QHash自带qhash函数,可以重载,默认用的是链地址法解决冲突
简单描述以及应用场景
QSet<T>:集合,
支持去重和判断元素是否存在的操作,适合处理集合运算或者需要维护元素唯一性的场景。
存储原理:QSet是一个模板类,它是一个
哈希表集合。QSet存储的值是不指明顺序的,也就是
随机存值的方式,但提供了
非常快速
的值查找功能。QSet中的数据必须是一个可转化(
可分配内存)的数据类型,例如不可以存QWidget而要存QWidget*。
优缺点---优点:
1、快速查找:QSet提供非常快速的值查找功能,因为它是基于哈希表实现的。
2、元素唯一性:QSet不允许存储重复的值,它通过哈希实现,没有顺序,只能通过迭代器遍历。
3、支持自定义哈希函数和冲突解决策略:QSet允许用户提供自定义的哈希函数和冲突解决策略,以便更好地控制数据集合的行为。
4、可用于自定义类型:QSet可以用于存储自定义类型的对象,只要这些类型提供了适当的哈希函数和相等性运算符。
优缺点---缺点:
1、无法保持元素的顺序:与QList和QVector等容器不同,QSet无法保持元素的插入顺序,因为它是基于哈希表实现的。
2、不支持随机访问:由于QSet是基于哈希表的,因此不支持随机访问。用户只能通过迭代器遍历QSet中的元素。
3、可能会产生哈希冲突:尽管QSet使用哈希表实现,但仍然可能会产生哈希冲突,即不同的键可能会哈希到同一个位置。这可能会
导致一些性能问题,例如需要使用额外的处理逻辑来解决冲突。
4、内存管理可能更复杂:使用QSet时需要注意内存管理问题,尤其是在处理自定义类型的对象时。如果QSet中的对象被删除或释放,
但仍然有指针指向它们,那么这些指针将变得无效。
代码示例
简单描述以及应用场景
QSparseArray<T>:稀疏数组,可以看做为一个 带"空位"索引号的 Map,即只将非默认值的元素存储在内部成员变量中,降低存储开销
存储原理:用于存储稀疏数组。它
基于哈希表实现,能够
高效地存储和访问数组中的元素。
优缺点---优点:
优缺点---缺点:
代码示例
Qt5.12已经不存在稀疏矩阵了
简单描述以及应用场景
QStack<T>:栈容器,支持入栈、出栈等操作。适用于需要按照先进后出的顺序处理元素的场景。
存储原理:
优缺点---优点:
优缺点---缺点:
代码示例
简单描述以及应用场景
QQueue<T>:队列容器,支持在队尾插入元素,在队头删除元素等操作,适合需要按照先进先出的顺序处理元素的场景。
存储原理:
优缺点---优点:
优缺点---缺点:
代码示例
简单描述以及应用场景
QPair<T1, T2>:一种轻量级容器,可以同时存储两个不同类型的对象,
适用于函数返回多个值时的场景。QPair是一个模板类,
用于存储一对值,
可以是不同的数据类型。它适用于需要将两个不同类型的值组合在一起的情况,但
不提供键值对的查找和排序等功能。不可以存QWidget而要存QWidget*
作为函数的返回值,可以返回两个相关的值,而不需要定义一个结构体或类。
作为容器的元素,可以存储键值对,例如QMap、QHash、QList等。可以将QPair放到这些容器当中去
作为算法的参数,可以传递两个相关的值,例如qSort、qStableSort等。
存储原理:
它通过
将两个值打包到一个对象中,实现了对两个值的方便访问和操作。QPair对象中包含了
first和second两个成员变量,分别用于存储第一个值
和第二个值。用户可以通过直接访问first和second成员变量来获取和修改这两个值。(
就是最普通的结构体)
优缺点---优点:
1、类型灵活:QPair是一个模板类,
可以存储任意类型的两个值,包括内置类型、自定义类型或其他Qt类型。这使得QPair在处理各种数据类型时非常灵活。
2、操作方便:QPair类模板提供了有用的成员函数和操作符重载,如括号运算符、比较运算符和赋值运算符等,
使得对有序对的操作变得简单方便。
3、实用性强:QPair在许多情况下都非常有用,特别是在需要将两个相关的值作为单个实体进行处理时。它可以用于存储和传递函数的多个返回值,或者用于在算法中存储和操作键值对等。
通过使用Qt QPair,开发人员可以更方便地组织和操作相关的数据。
优缺点---缺点:
在某些情况下,使用QPair可能会增加代码的复杂性
代码示例
使用STL常用算法
STL算法部分主要由头文件<algorithm>,<numeric>,<functional>组成。
STL中算法大致分为四类:
1、非可变序列算法:指不直接修改其所操作的容器内容的算法。
2、可变序列算法:指可以修改它们所操作的容器内容的算法。
3、排序算法:包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作。
4、数值算法:对容器内容进行数值计算。
使用STL迭代器
遍历一个容器可以使用
迭代器(iterators)来完成,迭代器提供了一个统一的方法来访问容器中的项目。Qt的容器类提供了两种类型
的迭代器:
Java风格迭代器和
STL风格迭代器。如果只是想按顺序遍历一个容器中的项目,那么还可以使用
Qt的foreach关键字。
Java风格迭代器:
Java风格的迭代器在Qt4中加入,比STL风格的迭代器更易于使用,但是以轻微的效率作为代价,它们的API以Java的迭代器类为模型。
对于每个容器类,
都有两种Java风格的迭代器类型:
一种是只读,另一种是
可读写。
在这里,我们只关注
QList和QMap。QLinkedList、QVector和QSet与QList的迭代器有同样的接口;
QHash与QMap迭代器也有同样的接口。
与STL风格的迭代器不同,
Java风格的迭代器指向项之间的位置,而
不是直接指向项。由于这个原因,它们指向第一项之前,或者最后一项之后,
或者两项之间。下面的图展示了包含4项的list的有效的迭代器位置,用红色箭头表示:
QList示例
QList正序和倒序遍历
下面是一个典型的例子,迭代器按顺序循环正序遍历QList<QString>的所有元素,并把它们打印到控制台上:
将要遍历的Qlist被传到QListIterator的构造函数,这时迭代器
定位在list的第一项之前("A"之前),接下来我们
调用hasNext()来检测迭代器后面是否
有一项,如果有,我们调用next()来跳过那一项,next()函数返回它跳过的那一项。
QList中倒序遍历:
QList移除
QListIterator没有提供从list中插入或移除项的函数
,想要实现插入和移除,你必须使用
QMutableListIterator
。
下面举例说明使用
QMutableListIterator从QList<int>中移除所有奇数。
QList修改
QListIterator的API:
QMap示例
QMapIterator,有点不同,因为他在
键值对上遍历。类似于QListIterator,QMapIterator提供了toFront()、toBack()、hasNext()、
next()、peekNext()、hasPrevious()、previous()以及peekPrevious()。键和值的
部分通过调用next()、peekNext()、previous()或
peekPrevious()返回的对象的key()和value()来获得。
STL风格的迭代器(实际上每个容器都自带着迭代器,效率当然高,而java风格的迭代器并不是,而是单独的类)
自从Qt2.0发布就可以使用STL风格的迭代器了,它们
适用于Qt和STL的泛型算法,并且对速度作了优化。
对于每个容器类,有两种STL风格的迭代器类型:只读的和可读写的。
尽可能使用只读的迭代器,因为它们比可读写的迭代器要快。
STL迭代器的API是以
数组中的指针为模型的,比如
++运算符将迭代器前移到下一项,
*运算符返回迭代器所指的那一项。事实上,
对于QVector和QStack,它们的项在内存中存储在相邻的位置,迭代器类型正是
T *,const迭代器类型正是
const T *。
在讨论中,我们重点放在QList和QMap,QLinkedList、QVector和QSet的迭代器类型与QList的迭代器有相同的接口;
同样地,
QHash的迭代器类型与QMap的迭代器有相同的接口。
QList示例
不同于Java风格的迭代器,
STL风格的迭代器直接指向每一项。
begin()函数返回指向容器中
第一项的迭代器。
end()函数返回指向容
器中
最后一项后面一个位置的迭代器,end()标记着一个
无效的位置,不可以被解引用,主要用在循环的break条件。如果list是空的,
begin()等于end(),所以我们永远不会执行循环。
如果是只读的,你可以使用
const_iterator、constBegin()和constEnd(),比如:
下面的表概括了STL风格迭代器的API:
QMap示例
对于QMap和QHash,
*运算符返回项的值,如果你想要
获得键,只需在迭代器上
调用key()。为了对称,迭代器类型还提供了
value()函数
来获得值。举个例子,下面是如何将QMap中的所有项打印到控制台上:
foreach关键字
如果你想要按顺序遍历容器中的所有项,你可以使用
Qt的foreach关键字。这个关键字是Qt特有的,与C++语言无关,并且使用了预处理器实现。
在QMap和QHash中,foreach可以获得键值对中值的部分。如果你遍历既想获得键又想获得值,则可以使用迭代器(这样是最快的),或者你可以这样写: