Студопедия

КАТЕГОРИИ:

Главная
Случайная страница
Познавательное
Новые статьи
Контакты
Заказать работу

Архитектура-(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)

Итераторы


12 Следующая ⇒


Итераторы не являются частью языка. Это концепция, используемая в программировании. Итераторы предоставляют способ последовательного доступа ко всем элементам составного объекта, не раскрывая его внутреннего представления.

Давайте посмотрим, как мы заполняли массив 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;

};


12 Следующая ⇒


Поделиться с друзьями:


Дата добавления: 2014年01月11日; Просмотров: 383; Нарушение авторских прав?; Мы поможем в написании вашей работы!


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



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




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

AltStyle によって変換されたページ (->オリジナル) /