- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
QT 4: программирование GUI на С++ - Жасмин Бланшет
Шрифт:
Интервал:
Закладка:
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():
QList<int> list = splitter->sizes();
QList<int>::const_iterator i = list.begin();
while (i != list.end()) {
do_something(*i);
++i;
}
Ниже дается пример неправильного программного кода:
// Неправильный программный код
QList<int>::const_iterator i = splitter->sizes().begin();
while (i != splitter->sizes().end()) {
do_something(*i);
++i;
}
Это происходит из-за того, что функция QSplitter::sizes() возвращает новый список QList<int> по значению при каждом новом своем вызове. Если мы не сохраняем возвращенное функцией значение, С++ автоматически удалит его еще до начала итерации, оставляя нам «повисший» итератор. Дело еще усугубляется тем, что на каждом новом шаге цикла функция QSplitter::sizes() должна генерировать новую копию списка из-за вызова функции splitter->sizes().end(). Поэтому используйте общее правило: когда применяются итераторы в стиле STL, всегда следует обрабатывать в цикле копию экземпляра контейнера, возвращаемого по значению.
При использовании итераторов в стиле Java, предназначенных только для чтения, нам не надо создавать копию. Итератор обеспечит копию незаметно для нас, гарантируя всегда просмотр в цикле данных, только что возвращенных функцией. Например:
QListIterator<int> i(splitter->sizes());
while (i.hasNext()) {
do_something(i.next());
}
Подобное копирование контейнера может показаться неэффективным, но это не так из-за оптимизации посредством так называемого неявного совместного использования даннъис (implicit sharing). Это означает, что операция копирования Qt—контейнера выполняется почти так же быстро, как копирование одного указателя. Только если скопированная строка изменяется, тогда данные действительно копируются — и все это делается автоматически и незаметно для пользователя. Поэтому неявное совместное использование иногда называют «копированием при записи» (copy on write).
Привлекательность неявного совместного использования данных заключается в том, что эта оптимизация выполняется так, что мы можем не думать о ней; она просто работает сама по себе и не требует от нас какого-то дополнительного программного кода. В то же время неявное совместное использование данных способствует тому, что программист следует четкому стилю, возвращая все объекты по значению. Рассмотрим следующую функцию:
01 QVector<double> sineTable()
02 {
03 QVector<double> vect(360);
04 for (int i = 0; i <360; ++i)
05 vect[i] = sin(i / (2 * M_PI));
06 return vect;
07 }
Вызов этой функции выглядит следующим образом:
QVector<double> table = sineTable();
В отличие от этого подхода, STL склоняет нас к передаче вектора в виде неконстантной ссылки, чтобы избежать копирования, происходящего из-за возвращения функцией значения, хранимого в переменной:

