КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Итераторы
Итераторы не являются частью языка. Это концепция, используемая в программировании. Итераторы предоставляют способ последовательного доступа ко всем элементам составного объекта, не раскрывая его внутреннего представления. Давайте посмотрим, как мы заполняли массив matrix на предыдущем занятии: for(size_t i=0;i<m.dim1();++i) for(size_t j=0;j<m.dim2();++j) m(i,j)=rand(); Для этого мы организовали два вложенных цикла. При этом нам понадобилось использовать две индексные переменные, вызывать две функции, а также следить за тем, чтобы переменная, наращиваемая до dim1() (это i), была первым индексом в m(i,j), а переменная, наращиваемая до dim2() (здесь это j), была вторым индексом. Однако перебор элементов можно организовать с помощью специального объекта – итератора. Имея в своем распоряжении итератор, мы можем сделать две вещи: а) получить доступ к текущему элементу, б) перейти к следующему элементу.
Изменим класс Matrix, добавив в него определение итератора и две функции: typedef int* iterator; iterator begin()const{return m;} iterator end()const{return m+size();} Функции begin() и end() возвращают значения, которые являются «границами» матрицы для итератора. Теперь заполнение массива мы можем организовать так: for(Matrix::iterator p=m.begin();p!=m.end();++p) *p=rand();
Здесь с помощью итератора p мы а) получаем доступ к текущему элементу путем разименования указателя, б) переходим к следующему элементу, производя инкремент указателя. Следуя идиоме итерационного перебора, напишем функцию, печатающую матрицу: void print_iter(const Matrix& m){ for(Matrix::iterator p=m.begin();p!=m.end();++p) std::cout<<*p<<','; } Следуя эффективной, идиоматичной схеме, программист избегает обычных ловушек, таких как ошибка, связанная с выходом за границы массива.
Теперь сделаем итератор для перебора элементов матрицы в обратном направлении. По прежнему для перехода к следующему элементу (элементу с меньшим адресом) будем использовать оператор инкремента. Теперь нам не подходит указатель, так как при вызове ++p итератор должен идти в сторону уменьшения. Поэтому нам придется определить класс итератора: Так как этот класс используется исключительно с классом Matrix, то определим этот класс внутри класса Matrix
class Matrix{ ... class reverse_iterator{ public: reverse_iterator(int *p):_p(p){} int& operator*(){return *_p;} void operator++(){--_p;} bool operator!=(reverse_iterator r)const{return _p!=r._p;} private: int *_p; }; ... };
Функции-члены класса Matrix, возвращающие граничные значения для данного итератора: reverse_iterator rbegin()const{return m+size()-1;} reverse_iterator rend()const{return m-1;}
Теперь перебор в обратном порядке выглядит так: for(Matrix::reverse_iterator r=m.rbegin();r!=m.rend();++r) *r=rand();
Недостатки приведенной концепции: необходимо определять по две дополнительные функции-члены контейнера (begin,end) для каждого типа итератора. Другая идиома для итератора, не имеющая этих недостатков: class m_iter{ public: m_iter(Matrix& m):_begin(m.m),_end(m.m+m.size()){} void First(){_p=_begin;} bool NotDone()const{return _p!=_end;} int& CurrentItem()const{return *_p;} void Next(){++_p;} private: int *_begin, *_end, *_p; }; Использование: m_iter mi(m); for(mi.First();mi.NotDone();mi.Next()) mi.CurrentItem()=rand();
Однако класс такого итератора должен иметь доступ к представлению контейнера, поэтому его нужно сделать другом контейнера:
class Matrix{ ... friend class m_iter; };
Дата добавления: 2014-01-11; Просмотров: 383; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |