Бублик Володимир Васильович Програмування - 2 Лекція 11. Ієрархічне програмування. Ітератори в контейнерах Лекції для студентів 2 курсу
Бублик Володимир Васильович
Програмування - 2
Лекція 11. Ієрархічне програмування.
Ітератори в контейнерах
Лекції для студентів 2 курсу
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 2
Повторення. Ітерований список
• class List• {• public:• List();• ~List();• void add(const Elem& elem);• const Elem& get() const;• void begin() const { _current = _start;}• void next() const { _current = _current -> _next; }• bool done() const { return _current == 0; }• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 3
Питання
• Чи залежить ітератор від самого контейнера? ― Так, оскільки він є частиною класу
Висновок:
• Невдале рішення: для користування ітератором ми повинні точно знати тип контейнера
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 4
Вивід списку
• ostream& operator <<(ostream & os, const List& lst)• {• lst.begin();• while (!lst.done())• {• os<<lst.get()<<':';• lst.next();• }• return os;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 5
Узагальнений вивід
• template <class Container>• ostream& operator <<(ostream & os, const Container& c)• {• c.begin();• while (!c.done())• {• os<<c.get()<<':';• c.next();• }• return os;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 6
Оцінка
• Узагальнені функції дають можливість генерувати потрібні засоби за єдиним шаблоном. Але це все ще невдале рішення з точки зору економії коду: кожен тип контейнера використовує власну конкретизацію шаблона
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 7
Аналіз вимог (1)
Функція оперує лише інтерфейсом ітератора• ostream& operator <<(ostream & os, const Itor& it)• {• it.begin();• while (!it.done())• {• os<<it.get()<<':';• it.next();• }• return os;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 8
Аналіз вимог (2)
Допускається як читання, так і запис елементів даних до контейнера
• void process (Itor& it)• {• for (it.begin(); !it.done(); it.next()) //C style• {• it.put ( it.get()+1 );• }• return;• }
1. Індивідуальні контейнери
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 10
Абстрактний ітератор
Зберемо інтерфейс в абстрактний клас• class Itor• {• public:• virtual ~Itor(){ };• virtual void begin () const = 0;• virtual const Elem& get () const =0;• virtual void put (const Elem &) = 0;• virtual bool done () const = 0;• virtual void next () const = 0;• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 11
Неітерований список
• class List• {• public:• List();• ~List();• List& add(const Elem& elem);• void del();• bool empty() const { return _amount==0;}• int amount() const { return _amount;}• private:• List (const List&);• List& operator= (const List&);
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 12
Неітерований список
• // Реалізація• protected:• struct Node• {• Elem _elem;• Node * _next;• Node * _prev;• };• Node * _start;• int _amount;• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 13
Змішування інтерфейсів
• class IteratedList: public Itor, public List• {• private:• mutable Node * _current; // на вузол списку• public:• IteratedList();• virtual void begin () const;• virtual const Elem& get() const;• virtual bool done() const;• virtual void next() const;• virtual void put(const Elem &);• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 14
Реалізація
• IteratedList :: IteratedList():_current(0)• {• };• const Elem& IteratedList :: get() const• {• return _current->_elem;• }• void IteratedList :: put (const Elem & elem)• {• _current->_elem = elem;• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 15
Реалізація
• bool IteratedList :: done() const• {• return _current == 0;• }
• void IteratedList :: next() const• {• _current= _current->_next;• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 16
Масив
• class Array• {• public:• explicit Array (size_t);• ~Array();• Elem& operator[] (size_t index);• const Elem& operator[] (size_t index) const;• size_t size() const;• private:• size_t _size;• Elem * _pElem;• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 17
Ітерований масив
• class IteratedArray: public Itor, public Array• {• private:• mutable size_t _current;• public:• IteratedArray(size_t n): Array(n){};• virtual void begin () const;• virtual const Elem& get() const;• virtual bool done() const;• virtual void next() const;• virtual void put(const Elem &);• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 18
Реалізація
• const Elem& IteratedArray::get() const• {• return (*this)[_current];• }• bool IteratedArray::done() const• {• return _current == size();• }• void IteratedArray::put(const Elem & elem)• {• (*this)[_current] = elem; return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 19
Реалізація
• IteratedArray :: IteratedArray (size_t n): Array(n)• {• };• void IteratedArray::begin() const• {• _current = 0; return;• }• void IteratedArray::next() const• {• ++_current; return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 20
Діаграма індивідуальних контейнерів
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 21
Сценарій спільного вживання
• // Створення ітерованого списку• IteratedList lst;• lst.add('a').add('b').add('c').add('d');•• // Створення ітерованого масиву• IteratedArray ar(5);• ar[0]='z'; ar[1]='y'; ar[2]='x'; ar[3]='w'; ar[4]='v';
• // Обробка спільною функцією process (Itor &)• process (lst); • process (ar);
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 22
Недолік
• Кожен ітератор в силу успадкування містить в собі екземпляр контейнера. Виникає проблема використання кількох ітераторів в межах одного контейнера (особливо за умови закритого копіювання контейнерів)
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 23
Питання
• Чи потрібен ітераторам інтерфейс списку і, відповідно, інтерфейс масиву?
2. Вбудовані індивідуальні ітератори
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 25
Підхід STL
• Спеціалізовані ітератори, вбудовані в конкретні класи контейнерів
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 26
Ітератор, вбудований до масиву
• class Array• {• public:• explicit Array (size_t);• ~Array();• Elem& operator[] (size_t index);• const Elem& operator[] (size_t index) const;• size_t size() const;
• class Iterator;• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 27
Агрегування масиву ітератором
• class Array::Iterator: public Itor• {• private:• Array * _toIterate;• mutable size_t _current;• public:• Iterator(Array& ar): _toIterate(&ar){};• virtual void begin () const;• virtual const Elem& get() const;• virtual bool done() const;• virtual void next() const;• virtual void put(const Elem &);
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 28
Ітератор, вбудований до списку
• class List• {• private: // Закриваємо реалізацію списку• struct Node• {• Elem _elem; Node * _next; Node * _prev;• };• Node * _start;• int _amount;• public:• class Iterator;
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 29
Агрегування списку ітератором
• class List::Iterator: public Itor• {• private:• List & _toIterate;• mutable Node * _current;• public:• Iterator(List& lst): _toIterate(lst),_current(0){};• virtual void begin () const;• virtual const Elem& get() const;• virtual bool done() const;• virtual void next() const;• virtual void put(const Elem &);
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 30
Сценарій спільного вживання
• // Створення списку і встановлення ітератора• List lst; lst.add('a').add('b').add('c').add('d');• List::Iterator ilst(lst);• // Створення масиву і встановлення ітератора• IteratedArray ar(5);• ar[0]='z'; ar[1]='y'; ar[2]='x'; ar[3]='w'; ar[4]='v';• Array::Iterator iar(ar);
• // Обробка спільною функцією process (Itor &)• process (ilst);• process (iar);
3. Копіювальні ітератори
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 32
Сортування масиву
• void sort(Array & ar)• {• for (size_t i=0; i<ar.size(); ++i)• {• size_t j=i;• for (size_t k=i+1; k<ar.size(); ++k)• if (ar[j]>ar[k]) j=k; // проблемно!!!• Elem x = ar[i]; ar[i] = ar [j]; ar[j] = x;• }• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 33
Ослаблене сортування масиву
• void sort(Array & ar)• {• for (size_t i=0; i<ar.size(); ++i)• {• size_t j=i;• for (size_t k=i+1; k<ar.size(); ++k)• if (ar[j]>ar[k]) • {Elem x = ar[i]; ar[i] = ar [j]; ar[j] = x;}• }• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 34
Ітератор масиву з копіювальним конструктором
• class Array::CopyIteratedArray• {• private:• Array * _par;• mutable size_t _current;• public:• explicit CopyIteratedArray(Array& );
CopyIteratedArray(const CopyIteratedArray& );• void begin() const { _current = 0;}• void next() const { ++_current;}• bool done() const { return _current == _par->size();}
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 35
Сортування масиву за копіювальним ітератором
• void it_sort(Array & ar)• {• Array::CopyIteratedArray it(ar);• for(it.begin(); !it.done(); it.next())• {• Array::CopyIteratedArray jt(it);• Array::CopyIteratedArray kt(it);• for (kt.next(); !kt.done(); kt.next())• if(jt.get()<kt.get())• {Elem tmp = jt.get(); jt.put(kt.get()); kt.put(tmp);}• }• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 36
Ітератор списку з копіювальним конструктором
• class List :: CopyIteratedList• {• private:• List & _lst;• mutable Node * _current;• public:• explicit CopyIteratedList (List&);• CopyIteratedList (const CopyIteratedList&);• void begin() const { _current = _lst._start;}• void next() const { _current = _current -> _next;}• bool done() const { return _current == 0;}
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 37
Сортування списку за копіювальним ітератором
• void it_sort(List & lst)• {• List::CopyIteratedList it(lst);• for(it.begin(); !it.done(); it.next())• {• List::CopyIteratedList jt(it);• List::CopyIteratedList kt(it);• for (kt.next(); !kt.done(); kt.next())• if(jt.get()<kt.get())• {Elem tmp = jt.get(); jt.put(kt.get()); kt.put(tmp);}• }• return;• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 38
Діаграма індивідуальних копіювальних ітераторів
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 39
Питання
• Як об'єднати інтерфейси• void it_sort(List & lst)• void it_sort(Array & ar)?
• Якби абстрактні класи мали конструктори, то ми б визначили абстрактний клас Itor з копіювальним конструктором
•Wag the dog!
4. Віртуальні конструкторив абстрактних ітераторах
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 41
Абстрактний ітератор з віртуальним конструктором
• class CloneItor• {• public:• virtual ~CloneItor(){ };• virtual CloneItor* clone () const=0;• virtual void begin () const = 0;• virtual const Elem& get () const =0;• virtual void put (const Elem &) = 0;• virtual bool done () const = 0;• virtual void next () const = 0;• };
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 42
Ітерований масив
• class Array :: CIteratedArray: public CloneItor• {• private:• Array & _ar;• mutable size_t _current;• public:• explicit CIteratedArray (Array& );• CIteratedArray (const CIteratedArray&);• CIteratedArray* clone() const;• void begin() const ;• void next() const;
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 43
• class List :: CIteratedList: public CloneItor• {• private:• List & _lst;• mutable Node * _current;• public:• explicit CIteratedList (List&);• CIteratedList (const CIteratedList&);• CIteratedList* clone() const;• void begin() const ;• void next() const;
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 44
Неповна відповідність сигнатур
Сигнатура абстрактного класу• virtual CloneItor* CloneItor :: clone() const;
Сигнатури і реалізації конкретизації• Array::CIteratedArray* Array::CIteratedArray :: clone() const• {• return new CIteratedArray (*this);• }• List::CIteratedList* List :: CIteratedList :: clone() const• {• return new CIteratedList (*this);• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 45
Застосування
• void sort(CloneItor& it)• {• for (it.begin(); !it.done(); it.next())• {• CloneItor * pjt = it.clone();• CloneItor * pkt = it.clone();• for (pkt->next(); !pkt->done(); pkt->next())• if (pjt->get()>pkt->get())• {Elem tmp = pjt->get(); pjt->put(pkt->get()); pkt->put(tmp);}
delete pjt;• delete pkt;• }• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 46
Діаграма клонованих ітераторів
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 47
Розширений інтерфейс ітератора
• class CloneItor• {• public:• virtual ~CloneItor(){ };• virtual CloneItor* clone() const=0;• virtual Elem& operator*() = 0;• virtual Elem& operator->() = 0;• virtual CloneItor& operator++() = 0;• virtual CloneItor& operator--() = 0;• virtual CloneItor operator++(int) = 0;• virtual CloneItor operator--(int) = 0;
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 48
Застосування розширеного ітератора
• void sort(CloneItor& it)• {• for (it.begin(); !it.done(); ++it)• {• CloneItor & jt = * it.clone();• CloneItor & kt = * it.clone();• for (kt->next(); ! kt->done(); ++kt)• if (jt.get()>kt.get())• { Elem tmp = *jt; *jt = *kt; *kt = tmp; }
delete & jt;• delete & kt;• }• }
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 49
Проблема
Присвоєння ітераторів
• Чисто віртуальну операцію присвоєння з абстрактного класу
• virtual Itor& Itor::operator=(const Itor&) = 0;
• неможна визначити в похідному класі• virtual IteratedList& List :: IteratedList ::
operator=(const IteratedList &);
© Бублик В.В. Програмування-2. Ієрархічне програмування. Ітератори в контейнерах 50
Висновки
• Розглянуті індивідуальні ітератори дають доступ до спільного інтерфейсу спеціалізовані контейнери
• Альтернатива універсальні контейнери з об'єднаним інтерфейсом