Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / LECS15.DOC
Скачиваний:
43
Добавлен:
16.04.2013
Размер:
114.18 Кб
Скачать

Перебор: итераторы и контейнеры

Контейнерные классы (container class) используются для хранения большого числа отдельных элементов. Типы stack и vect являются контейнерными классами. Многие операции с контейнерными классами предоставляют возможность удобного перебора (посещения) отдельных элементов. Кроме того, в С++ классы служат для достижения абстрактности. Абстракция – это игнорирование деталей, и класс игнорирует детали; он открыто предоставляет удобный способ для управления вычислительной задачей. В этой главе мы исследуем различные приемы для выполнения перебора и извлечения элементов класса. Один из способов состоит в создании итератора, функция которого – перебирать объекты в контейнерном классе. Итератор перемещается от элемента к элементу. Перебор послужит нам поводом для написания кода, использующего контейнерные классы, объекты – итераторы, а также (немного забегая вперед) алгоритмы из стандартной библиотеки шаблонов (STL).

Перебор

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

// переработать все a[I] и что–нибудь сделать

for (i = 0; i < size; ++i )

sum += a[i];

Однородный агрегат a [ ] обрабатывается элемент за элементом. Инструкция for задает определенный порядок перебора и управляется индексом i , который «растет на глазах» Конкретные порядок перебора и индекс цикла являются обычно деталями реализации, не влияющими на вычисления. Вот еще один способ выполнить те же вычисления:

for (j=size – 1; j ! = 0; --j)

sum += a [ j ];

Отвлеченно вычисления можно задать так:

пока не исчерпаны элементы

sum += следующий элемент

Реализуем следующий элемент типом указателя, который подходит для выбора объектов в контейнере. Давайте заменим класс vect из раздела 7.7, «Перегрузка операторов присваивания и индексирования», на стр. 203, добавив в него объекты – итераторы. Забегая вперед, назовем новый класс vector – так же, как контейнер в стандартной библиотеке шаблонов.

В файле vector. H

class vector {

public:

typedef int* iterator; // указатель vector :: int

explicit vector (int n =1);

vector (const vector& v);

vector (const int a [ ], int n)

~vector ( ) {delete [ ] bp; }

iterator begin ( ) const {return bp; }

iterator end ( ) const {return bp + size; }

int ub ( ) const {return size –1; } // верхняя граница

int& operator [ ] (int i); // проверка границ

vector& operator = (const vector& v);

private:

iterator bp; // базовый указатель

int size; // число элементов

};

Функции begin ( ) и end ( ) возвращают границы заданного вектора.

Код для суммирования такого агрегата с использованием итератора будет выглядеть так:

vector v (n);

vector :: iterator p;

int sum = 0;

……..

for (p = v. begin ( ); p != v/ end ( ); ++p)

sum += *p;

Идиома перебора здесь использует тип указателя и две границы для обработки в стандартном цикле всех элементов контейнера.

Итераторы

Объекты – указатели и идиома итерационного прибора делают очень простым написание многих стандартных алгоритмов для контейнерных классов, таких как класс vector. Напишем несколько подобных элементарных алгоритмов.

В файле vector. h

ostream& operator<< (ostream& out, const vector& v)

{

vector :: iterator p;

for (p = v. begin ( ) ; p != v. end ( ) ; ++p)

out << *p << ‘\t’;

out << end1;

return out;

}

istream& operator<< (istream& in, vector& v)

{

vector :: iterator p;

for (p = v. begin ( ) ; p != v. end ( ) ; ++p)

in >> *p;

return in;

}

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

Соседние файлы в папке Лекции