Qt学习笔记(七)容器类

容器类通常是用于在内存中存储给定类型的许多项的模板类。C++提供了很多容器,作为标准模板库STL的一部分,他们都包含在标准的C++库中。Qt提供了属于自己的容器类,所以在编写Qt程序时,既可以使用Qt容器也可以使用STL容器。Qt容器的主要优点是他们在所有的平台上在运行时都表现的一致,并且他们都是隐含共享的。Qt容器的另一个主要特征是易于使用的迭代器类,他们可以利用QDataStream变成数据流,而且他们通常可以使可执行文件中的代码量比相应的STL类中要少。在一些Qt/Embedded Linux支持的一些硬件平台上,通常使用Qt容器。

Qt既提供了诸如QVector<T>, QLinkedList<T>, QList<T>等的连续容器,也提供了诸如QMap<K, T>和QHash<K, T>等的关联容器。Qt还提供了在任意容器上执行相关操作的通用算法。如qSort()对一个连续容器进行排序,qBinaryFind()在经过排序的连续容器上执行一个二进制搜素。

QString是贯穿Qt应用编程接口的一个16位Unicode字符串,QByteArray是一个用来存储原始二进制数据的8位字符数组,QVariant类则可以存储绝大多数C++和Qt值类型。

1、连续容器

QVector<T>是一个与数组相似的数据结构,它可以把项存储到内存中相临近的位置。向量与普通C++数组的区别在于:向量知道自己的大小并且可以被重新定义大小。在向量末尾添加额外的项是非常快速的,在向量前面或者中间插入则是耗时的。

QVector<int> vect(3);

vect[0] = 1;

vect.append(3);

vect << 2; //上面三种方式都可以添加元素


QLinkedList<T>是一种把项存储到内存中不相邻的位置的数据结构,链表不支持快速的随机访问,提供了“常量时间”的插入和删除。

QLinkedList<QString> list;

list.append("hello");

list.append("world");

QLinkedList<QString>::iterator it = list.find("hello");

list.insert(it, "you");


QList<T>连续容器是一个”数组列表“,结合了单一类QVector<T>和QLinkedList<T>的最重要的优点。支持随机访问,而且界面和QVector一样基于索引的。在QList<T>的任意一端插入或移除项都是非常快速的。除非我们想在一个极大的列表中执行插入或者要求列表中的元素都必须占据连续的内存地址,否则QList<T>通常是最适合采用的多用途容器类。


QStringList类是被广泛用于Qt应用程序编程接口的QList<QString>的子类,QStringList还提供了一些特别的函数,以使得这种类对字符串的处理方式更通用。

QStack<T>是一个可以提供push(), pop(), top()的向量。

QQueue<T>是一个可以提供enqueue(), dequeue(), head()的列表。

上述容器类,值类型T可以是一个与int, double, 指针类型,具有默认构造函数,复制构造函数或者赋值操作符相似的类。这包括QByteArray、QDateTime、QRegExp、QString、QVariant。拍绳子QObject的类不具备资格,因为他们没有复制构造函数和复制操作符。在实际问题中,可以通过保存指针得到解决。

值类型T也可以是一个容器,但是在使用的时候必须使空格分开连续的尖括号,否则编译器会认为 >> 流操作符. Qlist<QVector<double>  > list;

Qt提供的两类迭代器用于遍历存储在容器中的项:java风格的迭代器和STL风格的迭代器。Java风格的迭代器易于使用,STL风格的迭代器可以结合Qt和STL的一般算法而具有强大的功能。

使用Java风格的迭代器,需要注意他们本身并不直接指向项,而是能够定位在第一项之前,最后一项之后,或者是相邻两项之间。

QList<int> list;

QListIterator<int> it(list);

while(it.hasNext())

{

dosomething();

} //迭代器通过容器遍历来初始化,在这一点,迭代器在第一项之前就被定位了。如果迭代器的右边有一项,则调用hasNext()函数会返回true, 向后迭代与此类似,但必须首先调用toBack(),以将迭代器定位到最后一项的后面。

使用STL风格的迭代器,C<T>::iterator it 和 C<T>::const_iterator it.两者区别是const_iterator 不允许修改数据。容器的begin()函数返回引用容器中第一项的STL风格的迭代器(如list[0]), end()函数返回”最后一个项之后“的项的迭代器。如果某个容器为空,则begin()等于end().

一个Qt函数返回一个容器。如果想使用STL风格的迭代器遍历某个函数的返回值,则必须复制此容器并且遍历这个副本。

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

QList<int> :: const_iterator it = list.begin();

while(it != list.end())

{

doSomething(*it);

it ++;

}

利用Java风格的迭代器时,不必复制容器。这个迭代器在后台自动生成一个副本,以确保总是遍历首先返回的函数的数据。



关联容器

QMap<K, T>是一个以升序键顺序存储键值对的数据结构。这种排列可以使它可以提供良好的查找和插入性能以及键序的迭代。因为要排序,故K类型必须提供operator<(). QMap还提供了函数key(), value()分别返回映射键的QList和映射值的QList。

QMap必须要求键值不同,而QMultiMap可以多个键值对有相同的键。


QHash<K, T>是一个在哈希表中存储键值对的数据结构,接口和QMap几乎相同,但是和QMap相比,他对K的模板类型有不同的要求,而且提供了比QMap更快的查找功能。

除了对存储在容器类中的所有值类型的一般要求,QHash<K, T>中的K类型还需要提供一个operator==(),并需要一个能够为键返回哈希值的全局qHash()函数的支持。

QHash为它内部的哈希表自动分配最初的存储区域,并在有项被插入或删除时重新划分所分配的存储区域的大小。也可以通过调用reserve()或者squeeze()来指定或者压缩希望存储到哈希表中项的数目,以进行性能调整。通常的做法是利用预期最大的项数目调用reserve(),然后插入数据,最后如果有多出的项,则调用squeeze()以使内存使用减少到最小。


通用算法:

qFind() 查找特定的值

qBianryFind() 在排序的容器中进行二分查找

qFill()  采用一个特定的值组装一个容器

qCopy() 将一个容器类的值复制到另一个容器类中

qSort() 快速排序


字符串、字符数组和变量

QString, QByteArray, QVariant这三种类与容器类有许多相似之处,在一些情况下可以用来代替容器类的使用。与容器类类似,这些类采用隐含共享来最优化内存和速度。

c++本身提供两种字符串:传统的C语言的以'\0'结尾的字符串和std::string类。与这两种字符串不同,QString支持16位Unicode值。

使用QString不必担心那些诸如分配足够的存储空间或确保数据以'\0'结尾等问题,可以将QString视作QChar向量。Qstring可以嵌入'\0'字符,length()函数返回包括被嵌入的'\0'字符的整个字符串的大小。QString为连接两个字符串提供了二进制+操作符,还为字符串后追加字符串提供了+= 操作符。QString的append()函数和+= 功能相同。使用 QString::sprintf()则是另外一种连接的方法:str.sprintf("%s %.1f%%", "perfect competition", 100.0);则str字符串被赋值为 "perfect competition 100.0%"

从其他字符串或数组建立一个字符串的另一个方法是使用arg(): str = QString("%1 %2 (%3s-%4s)").arg("permisssive").arg("society").arg(1950).arg(1970);在这个例子中,"permissive"会取代“%1”, "society"会取代"%2“, 1950取代%3, 1970取代”%4“。相比于sprintf, arg()方法更加安全,并且完全支持unicode编码,并且允许译码器对”%n"参数进行重新排序。

通过使用QString::number()静态函数,可以将数字转换成字符串。 str = QString::number(90);,或者也可以使用setNum()函数,如str.setNum(80);也可以使用toInt(), toDouble()等完成从字符串到数组的逆变换。bool ok; double d = str.toDouble(&ok); //参数为布尔型的指针。

QString的mid(arg1, arg2)返回给定位置arg1开始,共arg2个字符的字串。如 QString str = "new fjkdsfjdsfsf"; qDebug<<str.mid(9, 4); 缺省第二个参数表示从第一个参数开始到末尾。left()  right()函数用来完成相似的任务,他们都接收字符的数量n, 返回最左端或最右端的子串。

如果想查明一个字符串是否含有特定的字符,子串或者正则表达式,可以使用QString中的indexof()函数。对字符串进行操作时,需要判断是否为空,使用isEmpty()或者检查length是否为0.还有其他一些功能函数。

大多数情况下,从const char*字符串到QString的转换是自动完成的。例如str += ("jfkdf");为了明确的将const char*转换为QString,可以只使用一个QString强制转换,或者调用fromAscii()或者fromLatin1().要将QString转换为const char*, 可以使用toAscii()或者toLatin1(),他们返回QByteArray(), 而利用QByteArray::data()或QByteArray::constData(),可以将QByteArray转换为const char*。例如 printf("User: %s\n", str.toAscii().data());

当在QByteArray上调用data()或者constData()时,返回的字符串属于QByteArray对象。这意味着不必为内存泄露而担心,Qt将会为我们重新收回内存。另一方面,必须要注意不要太长时间的使用指针。如果QByteArray没有存储在一个变量中,那么他将在声明的末端自动删除。

QByteArray类有一个与QString很相似的应用编程接口与。诸如left(), right(), mid(), toLower(), toUpper(), trimmed(), simplified()等函数。QByteArray对存储原始的二进制数据以及8位编码的文本字符串非常有用,一般使用QString而不是QBytearray来存储文本,因为QString支持Unicode编码。

为方便起见,QByteArray自动保证”最后一项之后的项“总为'\0',这使得const char*可以很容易的将QByteArray传递给一个函数。QByteArray还支持嵌入的'\0'字符,以允许我们存储任意的二进制数据。

在某些情况下,我们需要在同一个变量中存储不同类型的数据。一种方法是像QByteArray或QString一样,对数据进行编码。例如字符串可以支持文本值或者以字符串形式支持数字值。这些方法很灵活,但它抛弃了C++的一些优点,尤其是类型的安全性和效率。QT提供了更加灵巧的方法,QVariant来处理那些能够支持不同数据类型的变量。

QVariant类可以支持许多Qt类型的值,除了基本的C++数字类型(如double, int等)还包括QBrush, QColor, QDateTime, QFont, QPoint, QSize, QString等。QVariant类也支持容器类,如QMap<QString, QVariant>, QList<QVariant>

在项视图、数据库模块和QSettings中广泛使用了变量,变量允许我们读写项数据、数据库数据以及任意与QVariant兼容的用户首选参数。

为了从QVariant中获取与图形用户界面相关的值,可以使用如下的:QVariant::value<T>模板成员函数:QIcon icon = variant.value<QIcon>.    value<T>()函数也可以用在非图形用户界面数据类型和QVariant之间进行转换。通常对于非图形用户界面数据类型,常使用toxx()作为转换函数, variant.toString();

如果自定义数据类型提供了默认的构造函数和副本构造函数的话,QVariant也可以用来存储他们。为此必须首先使用 Q_DECLARE_METATYPE()宏注册数据类型,尤其是在类定义下的头文件中: Q_DECLARE_METATYPE(BusinessCard);










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值