- •Учебное пособие
- •Введение
- •Объектно-ориентированный подход
- •Объектно-ориентированное программирование Абстрактные типы данных
- •Базовые принципы объектно-ориентированного программирования
- •Простейший ввод и вывод
- •Объект cout
- •Манипуляторы hex и oct
- •Другие манипуляторы
- •Объект cin
- •Операторы для динамического выделения и освобождения памяти (new и delete)
- •Базовые конструкции объектно-ориентированных программ Объекты
- •Понятие класса
- •Конструктор копирования
- •Конструктор explicit
- •Указатели на компоненты класса
- •Встроенные функции (спецификатор inline)
- •Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •Вложенные классы
- •Static-члены (данные) класса
- •Указатель this
- •Компоненты-функции static и const
- •Proxi-классы
- •Параметры ссылки
- •Независимые ссылки
- •Практические приемы ограничения числа объектов класса
- •Наследование (производные классы)
- •Конструкторы и деструкторы при наследовании
- •Виртуальные функции
- •Абстрактные классы
- •Виртуальные деструкторы
- •Множественное наследование
- •Виртуальное наследование
- •Перегрузка функций
- •Перегрузка операторов
- •Перегрузка бинарного оператора
- •Перегрузка унарного оператора
- •Дружественная функция operator
- •Перегрузка оператора []
- •Перегрузка оператора ()
- •Перегрузка операторов new и delete
- •Преобразование типа
- •Явные преобразования типов
- •Преобразования типов, определенных в программе
- •Шаблоны Параметризированные классы
- •Передача в шаблон класса дополнительных параметров
- •Шаблоны функций
- •Совместное использование шаблонов и наследования
- •Шаблоны класса и friend
- •Некоторые примеры использования шаблона класса Реализация smart-указателя
- •Классы поддерживающие транзакции
- •Задание значений параметров класса по умолчанию
- •Пространства имен
- •Ключевое слово using как директива
- •Ключевое слово using как объявление
- •Псевдоним пространства имен
- •Организация ввода-вывода
- •Состояние потока
- •Строковые потоки
- •Организация работы с файлами
- •Организация файла последовательного доступа
- •Создание файла произвольного доступа
- •Основные функции классов ios, istream, ostream
- •Основы обработки исключительных ситуаций
- •Перенаправление исключительных ситуаций
- •Исключительная ситуация, генерируемая оператором new
- •Генерация исключений в конструкторах
- •Задание собственной функции завершения
- •Спецификации исключительных ситуаций
- •Задание собственного неожиданного обработчика
- •Иерархия исключений стандартной библиотеки
- •Стандартная библиотека шаблонов (stl) Общее понятие о контейнере
- •Общее понятие об итераторе
- •Категории итераторов
- •Основные итераторы
- •Вспомогательные итераторы
- •Операции с итераторами
- •Контейнерные классы Контейнеры последовательностей
- •Контейнер последовательностей vector
- •Контейнер последовательностей list
- •Контейнер последовательностей deque
- •Ассоциативные контейнеры
- •Ассоциативный контейнер multiset
- •Ассоциативный контейнер set
- •Ассоциативный контейнер multimap
- •Ассоциативный контейнер map
- •Адаптеры контейнеров
- •Адаптеры stack
- •Адаптеры queue
- •Адаптеры priority_queue
- •Пассивные и активные итераторы
- •Алгоритмы
- •Алгоритмы сортировки sort, partial_sort, sort_heap
- •Алгоритмы поиска find, find_if, find_end, binary_search
- •Алгоритмы fill, fill_n, generate и generate_n
- •Алгоритмы equal, mismatch и lexicographical_compare
- •Математические алгоритмы
- •Алгоритмы copy, copy_backward, merge, unique и reverse
- •Алгоритмы работы с множествами
- •Алгоритмы swap, iter_swap и swap_ranges
- •Примеры реализации контейнерных классов Связанные списки
- •Реализация односвязного списка
- •Реализация двусвязного списка
- •Реализация двоичного дерева
- •Литература
- •Вопросы по курсу ооп
- •220013, Минск, п.Бровки, 6.
Общее понятие об итераторе
Для структурированных итераций, например, при обработке массивов:
for(i=0;i<size;i++) sm+=a[i];
порядок обращения к элементу управляется индексом i, который изменяется явно. Можно зафиксировать получение следующего элемента в компоненте-функции.
class vect
{ int *p; // массив чисел
int size; // размерность массива
int ind; // текущий индекс
public:
vect(); // размерность массива const
vect(int SIZE); // размерность массива size
~vect();
int ub(){return size-1;}
int next()
{ if(ind==pv->size)
return pv->p[(ind=0)++];
else
return pv->p[ind++];
}
};
Это соответствует тому, что обращение к объекту ограничивается использованием одного индекса ind. Другая возможность состоит в том, чтобы создать множество индексов и передавать функции обращения к элементу один из них. Это ведет к существенному увеличению числа переменных. Более удобным представляется создание отдельного, связанного с vect класса (класса итераций), в функции которого входит обращение к элементам класса vect. В приведенном ниже примере, для универсальности разрабатываемого класса vect использованы шаблоны классов vect и vect_iterator.
#include <iostream.h>
template<class T> // предварительное template объявление
class vect_iterator; // класса vect_iterator
template<class T>
class vect // шаблон класса vect
{ friend class vect_iterator<T>; // предварительное friend-объявление
T *p; // базовый указатель (массив)
int size; // размерность массива
public:
vect(int SIZE):size(SIZE)
{ p=new T[size];
for(int i=0; i<size; *(p+i++)=(T)i);
}
int ub(){return size-1;} // возвращается размер массива
void add() // изменение содержимого массива
{ for(int i=0; i<size; *(p+i++)+=1);}
~vect(){delete [] p;}
};
template<class T>
class vect_iterator
{ vect<T> *pv; // указатель на класс vect
int ind; // текущий индекс в массиве
public:
vect_iterator(vect<T> &v): ind(0),pv(&v){}
T &next();//возвращается текущее значение из массива (с индекса ind)
};
template<class T> // шаблон класса vect_iterator
T &vect_iterator<T>::next()
{ if(ind==pv->size)
return (T)pv->p[(ind=0)++];
else
return (T)pv->p[ind++];
}
void main()
{ vect<int> v(5);
vect_iterator<int> v_i1(v),v_i2(v); // создано 2 объекта-итератора
// для прохода по объекту vect
cout<<v_i1.next()<<' '<<v_i2.next()<<endl;
v.add(); // модификация объекта v
cout<<v_i1.next()<<' '<<v_i2.next()<<endl;
for(int i=0;i<v.ub();i++)
cout<<v_i1.next()<<endl;
}
Результат работы программы:
0 0
2 2
3
4
5
1
Полное отсоединение обращения от составного объекта позволяет объявлять столько объектов итераторов, сколько необходимо. При этом каждый из объектов итераторов может просматривать объект vect независимо от других.
Итератор представляет собой операцию, обеспечивающую последовательный доступ ко всем частям объекта. Итераторы имеют свойства, похожие на свойства указателей, и могут быть использованы для указания на элементы контейнеров первого класса. Итераторы реализуются для каждого типа контейнера. Также имеется целый ряд операций (*, ++ и другие) с итераторами, стандартными для контейнеров.
Если итератор a указывает на некоторый элемент, то ++a указывает на следующий элемент, а *a ссылается на элемент, на который указывает a.
Объект типа iterator может использоваться для ссылки на элемент контейнера, который может быть модифицирован, а const_iterator для ссылки на немодифицируемый элемент контейнера.
Еще один пример реализации контейнерного класса vect. В этом случае итерационный механизм реализован в непосредственно в классе vect.
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
template <class T>
class vect // шаблон класса vect
{ int size; // размерность массива
public:
typedef T* vect_iterator;
typedef const T* const_vect_iterator;
vect_iterator vv; // итератор контейнера
const_vect_iterator cv; // константный итератор
vect()
{ vv=new T; //
cv=vv; //
size=0;
}
~vect(){}
vect_iterator begin_v(); // итератор на начало вектора
vect_iterator end_v(); // итератор на конец вектора
void push_b(T); // добавление элемента в конец вектора
void pop_b(); // удаление элемента с конца вектора
void insert_v(T,T*); // добавление элемента в вектор
void erase_v(T*); // удаление элемента с конца вектора
};
template <class T>
void vect<T>::push_b(T a)
{ vect_iterator temp;
temp=new T[++size];
for(int i=0;i<size-1;i++)
*(temp+i)=*(vv+i);
*(temp+size-1)=a;
delete vv;
vv=temp;
}
template <class T>
T* vect<T>::begin_v()
{ return vv; }
template <class T>
T* vect<T>::end_v()
{ return vv+size; }
template <class T>
void vect<T>::pop_b()
{ vect_iterator temp;
temp=new T[--size];
for(int i=0;i<size;i++)
*(temp+i)=*(vv+i);
delete vv;
vv=temp;
}
template <class T>
void vect<T>::insert_v(T zn,T* adr)
{ int k=0;
vect_iterator temp;
temp=new T[++size];
for(vect_iterator i=vv;i<adr;i++)
*(temp+k++)=*i;
*(temp+k)=zn;
for(i=adr;i<vv+size-1;i++)
*(temp+ ++k)=*i;
delete vv;
vv=temp;
}
template <class T>
void vect<T>::erase_v(T* adr) // adr - итератор на удаляемый
{ int k=0; // элемент контейнера
vect_iterator temp;
temp=new T[--size]; // временный вектор
for(vect_iterator i=vv;i<adr;i++)
*(temp+k++)=*i;
for(i=adr+1;i<=vv+size;i++)
*(temp+k++)=*i;
delete vv; // освобождение памяти для старого вектора
vv=temp; // vv указывает нп новый вектор
}
void menu(void)
{ cout<<endl;
cout<<"1 - добавить элемент"<<endl;
cout<<"2 - pop последний элемент"<<endl;
cout<<"3 - erase элемент"<<endl;
cout<<"4 - print содержимое контейнера"<<endl;
cout<<"0 - окончание работы "<<endl;
}
main()
{ int count;
int choice;
int pos;
int val;
vect<int> Vect; // объект контейнер
vect<int>::vect_iterator itr; // итератор
int a;
cout<<"Сколько элементов вводится в вектор?"<<endl;
cin>>count;
for(int i = 0;i < count; i++)
{ cout<<"enter the element number "<<i+1<<endl;
cin>>a; // инициализация контейнера
Vect.push_b(a); // начальными значениями
}
while(1)
{ menu();
cout<<"? ";
cin>>choice;
cout<<endl;
switch(choice)
{ case 1:
cout<<"Введите значение и позицию "<<endl;
cin>>val>>pos;
Vect.insert_v(val,Vect.begin_v()+pos-1);
cout<<endl;
break;
case 2:Vect.pop_b();
cout<<"Элемент удален";
break;
case 3:
cout<<"Введите позицию элемента для удаления "<<endl;
cin>>pos;
Vect.erase_v(Vect.begin_v()+pos-1);
break;
case 4:
for(itr=Vect.begin_v();itr!=Vect.end_v();itr++)
cout<<*itr<<" ";
break;
case 0: return 0;
}
}
return 0;
}
