
- •8.2.1. Реалізація класів
- •8.2.2. Породження об’єктів
- •8.2.3. Виклик операцій
- •8.2.4. Використання успадкування
- •8.2.5. Реалізація залежностей
- •8.2.6. Шаблони, шаблони-класи
- •Параметри шаблонів, що опускаються
- •Приклади, які використовують вектори символів
- •8.2.8. Основні компоненти stl
- •8.2.8.1. Контейнери
- •Контейнери послідовностей
- •Впорядковані асоціативні контейнери
- •8.2.8.2. Параметричні (родові) алгоритми
- •8.2.8.3. Ітератори
- •8.2.8.4. Об’єкти-функції
- •8.2.8.5. Адаптери
- •8.2.8.6. Алокатори
- •8.2.9. Stl та об’єктно-орієнтоване програмування
8.2.8.3. Ітератори
Розуміння ітераторів є ключовим для вивчення STL в цілому та усвідомлення того, як найкраще використовувати бібліотеку STL. Параметричні алгоритми STL написані в термінах ітераторних параметрів, а контейнери STL забезпечують можливості ітераторів в алгоритмах. Ітератори відіграють роль «дротів» при з’єднанні. Найпростішим ітератором є звичайний покажчик мови С++, але можна визначити і багато інших ітераторів. Проте від цих інших ітераторів вимагається, щоб вони поводили себе, як покажчики відносно таких операцій, як ++ або *, у тому сенсі, що ++і пересуває ітератор і на наступний елемент, а * і видає значення елемента, відповідного ітератору і.
Розглянемо параметричну функцію accumulate, викликану з ітераторами first і beyond та значенням init:
accumulate(first, beyond, init);
вона підсумовує зі значенням init значення елементів, доступних за інтератором, починаючи з елемента, відповідного значенню ітератора first, та закінчуючи елементом, відповідним значенню ітератора, яке є попереднім beyond, та як результат повертає здобуту суму. Наприклад, можна дописати таку програму, яка обчислює та друкує суму елементів вектора:
#include <vector.h>
#include <algo.h>
#include <assert.h>
int main ()
{
cout <<« Параметрична функція accumulate.»<< end1;
int x[5] = {2,3,5,7,11};
//ініціалізація вектора vector1 значеннями від х[0] до х[4]
vector<int> vector1(&x[0], &x[5]);
int sum = accumulate(vector1.begin(),vector1.end(),0);
assert (sum == 28);
}
Ця програма використовує функцію accumulate для додавання цілих значень з вектора vector1, який розглядається за допомогою ітераторів vector1.begin( ) та vector1 .end ( ). Можна також застосовувати функцію accumulate до масиву х:
sum = accumulate (&x[0], &x[5], 0);
чи, наприклад, до списку значень типу подвійної точності (double):
double y[5] = {2.0, 3.0, 5.0 ,7.0, 11.0};
list<double> = list1(&y[0], &y[5]);
sum = accumulate(list1.begin(),list1.end(),0.0);
У кожному із цих випадків абстрактний зміст один і той самий — додавання початкового значення до всіх значень послідовностей.
Розглянемо докладніше спосіб використання ітераторів функцією accumulate. Цю функцію можна визначити так:
template <class InputIterator, class T>
T accumulate(InputIterator first, InputIterator beyond, T init)
{
while (first != beyond)
init = init + *first++;
return init;
}
У ній над ітераторами виконуються лише операція збільшення на 1 (постфіксна операція ++), операція розіменування * та операція перевірки на нерівність !=. Лише ці операції, а також префіксна операція ++ та операція перевірки на рівність = = вимагають категорії ітераторів, які називають ітераторами вводу (input iterators). Ще однією характеристикою ітераторів вводу, від якої вони дістали свою назву, є те, що від операції * вимагається лише одне: вона має читати з контейнера, але не записувати до нього. Ітератори виводу (output iterators) використовують ту саму операцію *, але тільки для запису даних в контейнер, а не для читання з нього.
У STL визначені ще три категорії ітераторів: прямі ітератори (forward iterators), двонапрямлені ітератори (bidirectional iterators) та ітератори вільного доступу (random access iterators). Між цими категоріями ітераторів встановлені ієрархічні відношення. Це означає, що кожна категорія ітераторів накладає нові вимоги на ітератори попередньої категорії, оскільки ітератор кожної категорії є одночасно ітератором всіх попередніх щодо неї за ієрархією категорій. Наприклад, двонапрямлений ітератор є також і прямим ітератором, а ітератор довільного доступу є також і прямим ітератором, а ітератор довільного доступу є також двонапрямленим та прямим ітератором.
Ступінь параметризованості алгоритмів, що їх використовують ітератори вводу, як, наприклад, accumulate, find та merge, вищий у алгоритмів, які потребують потужніших ітераторів. Це, скажімо, алгоритми sort, якому потрібний ітератор довільного доступу. Алгоритм sort не можна використовувати, наприклад, зі списковим контейнером, оскільки контейнери списку підтримують лише двонапрямлені ітератори і не підтримують ітераторів довільного доступу. Тому у STL контейнер списку має функцію-член, яка ефективно здійснює сортування, використовуючи двонапрямлені ітератори.