- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 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 склоняет нас к передаче вектора в виде неконстантной ссылки, чтобы избежать копирования, происходящего из-за возвращения функцией значения, хранимого в переменной: