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

ЖАНРЫ

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

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

Шрифт:

10 QString myTitle;

11 int myDuration;

12 };

Этот класс имеет конструктор, для которого необязательно указывать аргументы (хотя он может иметь до двух аргументов). Он также имеет конструктор копирования и оператор присваивания, которые обеспечиваются С++ по умолчанию. В этом классе достаточно обеспечить копирование между его членами, поэтому нам нет необходимости реализовывать свои собственные конструктор копирования и оператор присваивания.

Qt имеет две категории итераторов, используемых для прохода по элементам контейнера: итераторы в стиле Java и итераторы в стиле STL. Итераторами в стиле Java легче пользоваться, в то время как итераторы в стиле STL более мощные и могут использоваться совместно с алгоритмами Qt

и STL.

С каждым классом—контейнером могут использоваться два типа итераторов в стиле Java: итератор, используемый только для чтения, и итератор, используемый как для чтения, так и для записи. Классами итераторов первого типа являются QVectorIterator<T>, QLinkedListIterator<T> и QListIterator<T>. Соответствующие итераторы чтения—записи имеют слово Mutable (изменчивый) в их названии (например, QMutableVectorIterator<T>). В дальнейшем мы основное внимание будем уделять итераторам списка QList; итераторы связанных списков и векторов имеют тот же самый программный интерфейс.

Рис. 11.3. Допустимые позиции итераторов в стиле Java.

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

QList<double> list;

QListIterator<double> i(list);

while (i.hasNext) {

do_something(i.next);

}

Итератор инициализируется контейнером, для прохода по которому он будет использован. В этот момент итератор располагается непосредственно перед первым элементом. Вызов функции hasNext возвращает true, если имеется элемент справа от итератора. Функция next возвращает элемент, расположенный справа от итератора, и перемещает итератор в следующую допустимую позицию.

Проход в обратном направлении выполняется аналогично, с тем отличием, что сначала вызывается функция toBack для размещения итератора после последнего элемента.

QListIterator<double> i(list);

i.toBack;

while (i.hasPrevious) {

do_something(i.previous);

}

Функция hasPrevious возвращает true, если имеется элемент слева от итератора; функция previous возвращает элемент, расположенный слева от итератора, и перемещает итератор назад на одну позицию. Возможен другой взгляд на функции next и previous: они возвращают тот элемент, через который только что прошел итератор.

Рис. 11.4. Влияние функций previous и next на итераторы в стиле Java.

Допускающие запись итераторы (mutable iterators) имеют функции для вставки, модификации и удаления элементов в ходе просмотра контейнеров. В показанном ниже цикле из списка удаляются отрицательные числа:

QMutableListIterator<double> i(list);

while (i.hasNext) {

if (i.next < 0.0)

i.remove;

}

Функция remove всегда работает с последним пройденным элементом.

Она так же ведет себя при проходе элементов в обратном направлении:

QMutableListIterator<double> i(list);

i.toBack;

while (i.hasPrevious) {

if (i.previous < 0.0)

i.remove;

}

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

QMutableListIterator<double> i(list);

while (i.hasNext) {

int val = i.next;

if (val < 0.0)

i.setValue(-val);

}

Кроме того, можно вставлять элемент в текущую позицию итератора с помощью функции insert. После этого итератор перемещается в позицию между новым элементом и следующим за ним.

Кроме итераторов в стиле Java каждый класс последовательных контейнеров C<T> имеет итераторы в стиле STL двух типов: С<Т>::iterator и C<T>::const_iterator. Они отличаются тем, что итератор const_iterator не позволяет модифицировать данные.

Функция контейнера begin возвращает итератор в стиле STL, ссылающийся на первый элемент контейнера (например, list[0]), в то время как функция контейнера end возвращает итератор, ссылающийся на элемент «после последнего элемента» (например, list[5] для списка размером 5). Если контейнер пустой, функции begin и end возвращают одинаковое значение. Это может использоваться для проверки наличия хотя бы одного элемента в контейнере, хотя для этой цели более удобно пользоваться функцией isEmpty.

Рис. 11.5. Допустимые позиции итераторов в стиле STL.

Синтаксис применения итераторов в стиле STL моделирует синтаксис применения указателей С++. Мы можем использовать операторы ++ и —— для перехода на следующий или предыдущий элемент, а также унарный оператор * для извлечения значения элемента из позиции текущего итератора. Для вектора vector<T> типы итераторов iterator и const_iterator определяются просто как typedef для Т * и const T *. (Так можно делать, поскольку QVector<T> хранит свои элементы в последовательных адресах памяти.)

В показанном ниже примере каждое значение в списке QList<double> заменяется своим абсолютным значением:

QList<double>::iterator i = list.begin;

while (i ! = list.end) {

*i = qAbs(*i);

++i;

}

Несколько функций Qt возвращают контейнер. Если мы хотим в цикле обработать такое возвращенное значение функции, используя итератор в стиле STL, мы должны сделать копию контейнера и в цикле обрабатывать эту копию. Например, приводимый ниже программный код показывает, как правильно следует обрабатывать в цикле список типа QList<int>, возвращенный функцией QSplitter::sizes:

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