Студопедия

КАТЕГОРИИ:


Архитектура-(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; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.007 сек.