В данной главе мы также рассмотрим классы QString, QByteArray и QVariant, поскольку они имеют много общего с контейнерами. QString представляет собой 16-битовую строку символов в коде Unicode, которая широко используется в программном интерфейсе Qt. QByteArray является массивом 8-битовых символов типа char, которым удобно пользоваться для хранения произвольных двоичных данных. QVariant может хранить значения большинства типов С++ и Qt.
Последовательные контейнеры
Вектор QVector представляет собой структуру данных, в которой элементы содержатся в соседних участках оперативной памяти. Вектор отличается от обычного массива С++ тем, что знает свой собственный размер и этот размер может быть изменен. Добавление элементов в конец вектора выполняется достаточно эффективно, но добавление элементов в начало вектора или вставка в его середину могут быть неэффективны.
Рис. 11.1. Вектор чисел двойной точности.
Если нам заранее известно необходимое количество его элементов, мы можем задать начальный размер при его определении и использовать оператор [ ] для заполнения его элементами; в противном случае мы должны либо затем изменить его размер, либо добавлять элементы в конец вектора. В приведенном ниже примере мы указываем начальный размер вектора:
QVector vect(3);
vect[0] = 1.0;
vect[1] = 0.540302;
vect[2] = -0.416147;
Ниже та же самая задача решается путем объявления пустого вектора и применения функции append, которая добавляет элементы в конец вектора:
QVector vect;
vect.append(1.0);
vect.append(0.540302);
vect.append(-0.416147);
Вместо append можно использовать оператор <<:
vect << 1.0 << 0.540302 << -0.416147;
Организовать цикл просмотра элементов вектора можно при помощи оператора [ ] и функции count:
double sum = 0.0;
for (int i = 0; i < vect.count; ++i)
sum += vect[i];
Элементы вектора, которым не было присвоено какое-нибудь значение явным образом, инициализируются при помощи стандартного конструктора класса элемента. Основные типы и указатели инициализируются нулевым значением.
Вставка элементов в начало или в середину вектора QVector, а также удаление элементов из этих позиций могут быть неэффективны для больших векторов. По этой причине Qt предлагает связанный список QLinkedList — структуру данных, элементы которой располагаются не в соседних участках памяти. В отличие от векторов, связанные списки не поддерживают произвольный доступ к элементам, но обеспечивают «константное время» выполнения операций вставки и удаления.
Рис. 11.2. Связанный список значений типа double.
Связанные списки не обеспечивают оператор [ ], поэтому необходимо использовать итераторы для прохода по всем элементам. Итераторы также используются для указания позиции элементов. Например, в следующем фрагменте программного кода выполняется вставка строки «Tote Hosen» между «Clash» и «Ramones»:
QLinkedList list;
list.append("Clash");
list.append("Ramones");
QLinkedList::iterator i = list.find("Ramones");
list.insert(i, "Tote Hosen");
Более подробно итераторы будут рассмотрены позже в данном разделе.
Последовательный контейнер QList является «массивом—списком», который сочетает в одном классе наиболее важные преимущества QVector и QLinkedList. Он поддерживает произвольный доступ, и его интерфейс основан на индексировании подобно применяемому векторами QVector. Вставка в конец или удаление последнего элемента списка QList выполняется очень быстро, а вставка в середину выполняется быстро для списков, содержащих до одной тысячи элементов. Если не требуется вставлять элементы в середину больших списков и не нужно, чтобы элементы списка занимали последовательные адреса памяти, то QList обычно будет наиболее подходящим контейнером общего назначения.
Класс QStringList является подклассом QList, который широко используется в программном интерфейсе Qt. Кроме наследуемых от базового класса функций он имеет несколько дополнительных функций, увеличивающих возможности класса по обработке строк. Класс QStringList будет обсуждаться в последнем разделе этой главы.
QStack и QQueue — еще два примера удобных подклассов: QStack — это вектор, для работы с которым предусмотрены функции push, pop и top. QQueue — это список, для работы с которым предусмотрены функции enqueue, dequeue и head.