Menu
Coddy logo textTech

Итераторы

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy — урок 72 из 104.

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

Каждый контейнер STL предоставляет методы begin() и end(). Итератор begin() указывает на первый элемент, в то время как end() указывает на элемент, следующий за последним — сторожевое значение (sentinel), которое отмечает место остановки:

#include <vector>
#include <iostream>

int main() {
    std::vector<int> nums = {10, 20, 30};
    
    for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
        std::cout << *it << " ";  // Разыменование для получения значения
    }
    // Вывод: 10 20 30
}

Ключевое слово auto значительно упрощает объявление итераторов:

for (auto it = nums.begin(); it != nums.end(); ++it) {
    *it *= 2;  // Изменяем элементы через итератор
}
// nums теперь {20, 40, 60}

Итераторы делятся на различные категории в зависимости от их возможностей. Итераторы произвольного доступа (например, итераторы vector) поддерживают арифметические операции, такие как it + 3 или it1 - it2.

Двунаправленные итераторы (из list, map) могут перемещаться вперед и назад с помощью ++ и --. Однонаправленные итераторы могут перемещаться только в одном направлении.

Для обратного обхода используйте rbegin() и rend():

for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
    std::cout << *rit << " ";  // Выводит в обратном порядке
}
challenge icon

Задание

Легко

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

Вы организуете свой код в двух файлах:

  • Inventory.h: Определите класс Inventory, который управляет коллекцией количеств предметов, хранящихся в std::vector<int>.

    Ваш класс должен предоставлять следующие методы:

    • addItem(int quantity) — добавляет количество предметов в инвентарь
    • printForward() — использует итераторы с begin() и end() для вывода всех количеств, разделенных пробелами, за которыми следует символ новой строки
    • printReverse() — использует обратные итераторы с rbegin() и rend() для вывода всех количеств в обратном порядке, разделенных пробелами, за которыми следует символ новой строки
    • doubleAll() — использует итераторы для обхода вектора и удвоения каждого количества на месте
    • getTotal() — использует итераторы для вычисления и возврата суммы всех количеств

    Используйте ключевое слово auto для объявлений итераторов, чтобы код оставался чистым.

  • main.cpp: Считайте четыре целых числа (каждое на отдельной строке), представляющих количество предметов.

    Создайте объект Inventory и добавьте все четыре количества. Затем продемонстрируйте использование итераторов:

    1. Выведя "Forward: ", а затем вызвав printForward()
    2. Выведя "Reverse: ", а затем вызвав printReverse()
    3. Выведя "Total: ", за которым следует результат getTotal()
    4. Вызвав doubleAll() для изменения количеств
    5. Выведя "After doubling: ", а затем вызвав printForward()
    6. Выведя "New total: ", за которым следует результат getTotal()

Например, при входных данных 10, 25, 15 и 30:

Forward: 10 25 15 30 
Reverse: 30 15 25 10 
Total: 80
After doubling: 20 50 30 60 
New total: 160

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

Шпаргалка

Итераторы — это объекты, которые предоставляют единообразный способ доступа к элементам в контейнерах. Они действуют как обобщенные указатели, которые знают, как перемещаться по контейнеру.

Каждый контейнер STL предоставляет методы begin() и end(). Итератор begin() указывает на первый элемент, в то время как end() указывает на элемент, следующий за последним:

std::vector<int> nums = {10, 20, 30};

for (std::vector<int>::iterator it = nums.begin(); it != nums.end(); ++it) {
    std::cout << *it << " ";  // Разыменование для получения значения
}

Используйте ключевое слово auto, чтобы упростить объявление итераторов:

for (auto it = nums.begin(); it != nums.end(); ++it) {
    *it *= 2;  // Изменение элементов через итератор
}

Категории итераторов в зависимости от их возможностей:

  • Итераторы произвольного доступа (например, vector) поддерживают арифметические операции, такие как it + 3 или it1 - it2
  • Двунаправленные итераторы (например, list, map) могут перемещаться вперед и назад с помощью ++ и --
  • Однонаправленные итераторы могут перемещаться только в одном направлении

Для обратного обхода используйте rbegin() и rend():

for (auto rit = nums.rbegin(); rit != nums.rend(); ++rit) {
    std::cout << *rit << " ";  // Выводит в обратном порядке
}

Попробуйте сами

#include <iostream>
#include "Inventory.h"

using namespace std;

int main() {
    // Считать четыре целых числа
    int q1, q2, q3, q4;
    cin >> q1;
    cin >> q2;
    cin >> q3;
    cin >> q4;

    // TODO: Создать объект Inventory

    // TODO: Добавить все четыре количества в инвентарь

    // TODO: Вывести "Forward: ", затем вызвать printForward()

    // TODO: Вывести "Reverse: ", затем вызвать printReverse()

    // TODO: Вывести "Total: ", а затем результат getTotal()

    // TODO: Вызвать doubleAll() для изменения количеств

    // TODO: Вывести "After doubling: ", затем вызвать printForward()

    // TODO: Вывести "New total: ", а затем результат getTotal()

    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование