Чтение онлайн

ЖАНРЫ

QT 4: программирование GUI на С++

Саммерфилд Марк

Шрифт:

Последовательные контейнеры

Вектор QVector<T> представляет собой структуру данных, в которой элементы содержатся в соседних участках оперативной памяти. Вектор отличается от обычного массива С++ тем, что знает свой собственный размер и этот размер может быть изменен. Добавление элементов в конец вектора выполняется достаточно эффективно, но добавление элементов в начало вектора или вставка в его середину могут быть неэффективны.

Рис. 11.1. Вектор чисел двойной точности.

Если

нам заранее известно необходимое количество его элементов, мы можем задать начальный размер при его определении и использовать оператор [ ] для заполнения его элементами; в противном случае мы должны либо затем изменить его размер, либо добавлять элементы в конец вектора. В приведенном ниже примере мы указываем начальный размер вектора:

QVector<double> vect(3);

vect[0] = 1.0;

vect[1] = 0.540302;

vect[2] = -0.416147;

Ниже та же самая задача решается путем объявления пустого вектора и применения функции append, которая добавляет элементы в конец вектора:

QVector<double> 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<T>, а также удаление элементов из этих позиций могут быть неэффективны для больших векторов. По этой причине Qt предлагает связанный список QLinkedList<T> — структуру данных, элементы которой располагаются не в соседних участках памяти. В отличие от векторов, связанные списки не поддерживают произвольный доступ к элементам, но обеспечивают «константное время» выполнения операций вставки и удаления.

Рис. 11.2. Связанный список значений типа double.

Связанные списки не обеспечивают оператор [ ], поэтому необходимо использовать итераторы для прохода по всем элементам. Итераторы также используются для указания позиции элементов. Например, в следующем фрагменте программного кода выполняется вставка строки «Tote Hosen» между «Clash» и «Ramones»:

QLinkedList<QString> list;

list.append("Clash");

list.append("Ramones");

QLinkedList<QString>::iterator i = list.find("Ramones");

list.insert(i, "Tote Hosen");

Более подробно итераторы будут рассмотрены позже в данном разделе.

Последовательный контейнер QList<T> является «массивом—списком», который сочетает

в одном классе наиболее важные преимущества QVector<T> и QLinkedList<T>. Он поддерживает произвольный доступ, и его интерфейс основан на индексировании подобно применяемому векторами QVector. Вставка в конец или удаление последнего элемента списка QList<T> выполняется очень быстро, а вставка в середину выполняется быстро для списков, содержащих до одной тысячи элементов. Если не требуется вставлять элементы в середину больших списков и не нужно, чтобы элементы списка занимали последовательные адреса памяти, то QList<T> обычно будет наиболее подходящим контейнером общего назначения.

Класс QStringList является подклассом QList<QString>, который широко используется в программном интерфейсе Qt. Кроме наследуемых от базового класса функций он имеет несколько дополнительных функций, увеличивающих возможности класса по обработке строк. Класс QStringList будет обсуждаться в последнем разделе этой главы.

QStack<T> и QQueue<T> — еще два примера удобных подклассов: QStack<T> — это вектор, для работы с которым предусмотрены функции push, pop и top. QQueue<T> — это список, для работы с которым предусмотрены функции enqueue, dequeue и head.

Во всех до сих пор рассмотренных контейнерах тип элемента T может являться базовым типом (например, int или double), указателем или классом, который имеет стандартный конструктор (т.е. конструктор без аргументов), конструктор копирования и оператор присваивания. К таким классам относятся QByteArray, QDateTime, QRegExp, QString и QVariant. Этим свойством не обладают классы Qt, которые наследуют QObject, поскольку последний не имеет конструктора копирования и оператора присваивания. На практике это не составляет проблему, потому что мы можем просто хранить в контейнере указатели на такие типы данных, а не сами объекты QObject.

Тип T также может быть контейнером; в этом случае следует иметь в виду, что необходимо разделять рядом стоящие угловые скобки пробелами, в противном случае компилятор будет сбит с толку, воспринимая >> как оператор. Например:

QList<QVector<double> > list;

Кроме только что упомянутых типов в качестве типа элементов контейнера может задаваться любой пользовательский класс, отвечающий описанным ранее критериям. Ниже дается пример такого класса:

01 class Movie

02 {

03 public:

04 Movie(const QString &title = "", int duration = 0);

05 void setTitle(const QString &title) { myTitle = title; }

06 QString title const { return myTitle; }

07 void setDuration(int duration) { myDuration = duration; }

08 QString duration const { return myDuration; }

09 private:

Поделиться с друзьями: