07 containers

44
Бублик Володимир Васильович Програмування - 2 Лекція 7. Об'єктне програмування. Контейнерні класи Лекції для студентів 2 курсу

Upload: olegapster

Post on 22-Dec-2014

354 views

Category:

Entertainment & Humor


5 download

DESCRIPTION

 

TRANSCRIPT

Бублик Володимир Васильович

Програмування - 2

Лекція 7. Об'єктне програмування.

Контейнерні класи

Лекції для студентів 2 курсу

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

2

Повторення: агрегати

• Агрегати містять в собі інші об'єкти у вигляді атрибутів або відсилок чи указників на них

• Звичайно атрибути закриті для доступу зовні• Доступ до атрибутів та заміна їх значень

виконуються відповідно за допомогою селектора та модифікатора

• Атрибути можуть бути зв'язані одне з одним, а тому модифікатор кожного з атрибутів повинен зберігати повноцінність інших

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

3

Контейнер

• Агрегат, здатний містити, як правило, значну кількість схожих (однотипних) об'єктів

• Спосіб агрегування ― композиція• Види контейнерів: масив, послідовність, список,

черга, стек, дек• Спосіб доступу: довільний або послідовний

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

4

Масив

В стилі С

• T ar [m] = {a0, a1, …, am-1};

• T * p = new T [n];

Проблеми:• Неспроможність відрізнити указник одиночного

даного від масиву• Нездатність контролювати вихід індексу за межі

масиву

Перевага• Довільний доступ до елементу масиву за індексом

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

5

Приклад1

• double a[10] = {0,1,2,3,4,5,6,7,8,9};• cout<<sizeof(a)/sizeof(double)<<endl; //10• g(a);

• // Масив забув свій розмір• void g(double a[])• {• cout<<"Can't calculate size"<<endl;• cout<< sizeof(a)/sizeof(double)<< endl;//0• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

6

Приклад2

• double a[10] = {0,1,2,3,4,5,6,7,8,9};• cout<<sizeof(a)/sizeof(double)<<endl; //10• g(a);

• // Указник не знає, що він масив• void g(double * a)• {• cout<<"Can't calculate size"<<endl;• cout<< sizeof(a)/sizeof(double)<< endl;//0• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

7

Приклад3

• void h(double * a, int n)• {• for (int i=0; i<n; ++i)• a[i]=i;• }

• // Функція приймає адресу за масив• double a= 1;• h(&a, 1000);

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

8

Створення/видалення

Як гарантувати парність new/delete new[]/delete[]?

• double * u = new double (12345);• double * v = new double [12345];

• delete [] u;• delete v;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

9

Клас масивів

• class Array• {• public:• explicit Array (size_t);• ~Array();• // Селектор-модифікатор• double& operator[] (size_t index);• // Модифікатор• const double & operator[] (size_t index) const;• // Розмірність• size_t size() const;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

10

Масив чисел

• // Клас для обробки помилкових ситуацій• class BadArray;• private:• // Атрибут розмірності• size_t _size;• // Власне масив• double * _pElem;• // Не визначені для масивів:• Array (const Array&);• Array& operator= (const Array&);• };

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

11

Конструктор масиву

• Array::Array (size_t sz):• _size(sz), _pElem (new double[_size])• {• if (_pElem == 0)• throw BadArray ("No more space for

you");• #ifndef NDEBUG• cout<<"Array created ["<<_size<<‘]'<<endl;• #endif• return;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

12

Деструктор

Розробник класу гарантує симетричність видалення створенню

• Array::~Array()• {• #ifndef NDEBUG• cout<<"Array of size ("<<_size<<")

deleted"<<endl;• #endif• delete [] _pElem;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

13

Ініціалізація

Чим наповнено масив дійсних чисел після його створення? ― Сміттям

• Array ar(10);• for (int i=0; i<10; ++i)• cout<<ar[i]<<‘,’• cout<<endl;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

14

Масив об'єктів

• class ArrayOfPoints• {• public:• explicit Array (size_t);• ~Array();• Point& operator[] (size_t index);• const Point & operator[] (size_t index) const;• size_t size() const;• private:• size_t _size;• Point * _pElem;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

15

Конструктор масиву

• ArrayOfPoints::ArrayOfPoints (size_t sz):• _size(sz),• // Виклик _size конструкторів• _pElem (new Point [_size])• {• if (_pElem == 0)• throw BadArray ("No more space for

you");• #ifndef NDEBUG• cout<<"Array created ["<<_size<<‘]'<<endl;• #endif• return;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

16

Конструктор масиву

• NB. Клас елемента масиву повинен мати конструктор без параметрів

// Ініціалізація// без проблемclass Foo{public:

Foo();};

// Ініціалізація// неможливаclass Foox{public:

Foox (int x);};

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

17

Конструктор масиву

• NB. Клас елемента масиву повинен мати конструктор без параметрів

// Ініціалізація// без проблемclass Foo{public:

Foo();};

// Знову// без проблемclass Foox{public:

Foox (int x=0);};

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

18

Індексування: селектор/модифікатор

Небезпечна, взагалі кажучи, операція, оскільки фактично відкриває повний доступ до закритої частини класу

Для контейнерів прийнятна, оскільки контейнери не мають обмежень на призначені для зберігання дані

• double& Array::operator[] (size_t index)• {• if (index<0 || index>=_size)• throw BadArray("Bad index: ", index);• return _pElem [index];• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

19

Чистий селектор

Призначений для доступу передусім до контейнера, переданого параметром за допомогою сталої відсилки

• double Array::operator[] (size_t index) const• {• if (index<0 || index>=_size)• throw BadArray("Bad index: ", index);• return _pElem [index];• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

20

Обробник помилок

• class Array::BadArray• {• private:• string _reason;• size_t _index;• public:• BadArray(string reason="", size_t index=0);• ~BadArray();• };• ostream& operator<<• (ostream &os, const Array::BadArray& seq);

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

21

Проблема наповненості

Масив як контейнер не здатний зберігати менше даних, ніж його ємність: індексування контролює лише вихід індексу за межі масиву, але не перевіряє, чи був елемент попередньо визначений

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

22

Обмежена послідовність

Розмістимо n членів послідовності s на перших n місцях масиву a розмірності n

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

23

Діаграма класів

• Масив агрегований як компонент послідовності

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

24

Послідовність. Версія 1

• #include <limits> • class Sequence• {• public:• explicit Sequence(size_t capacity =_seqBlock);• ~Sequence();• Sequence& putAfter• (double elem, • size_t ind=std::numeric_limits<size_t>::max());• Sequence& remove• (size_t

ind=std::numeric_limits<size_t>::max());

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

25

Послідовність. Версія 1

• const double& operator[] (size_t index) const;• double & operator[] (size_t index);• // Поточна ємність • size_t capacity() const;• // Поточний розмір• size_t size() const;• // Чи порожня послідовність?• bool empty() const;• // Очистити послідовність• void clear();

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

26

Послідовність. Версія 1

• class BadSeq;• private:• size_t _size;• Array _seqArray;• // Стандартний розмір блока контейнера• static size_t _seqBlock;• Sequence (const Sequence&);• Sequence& operator=(const Sequence&);• };

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

27

Конструктор/деструктор

• // Створити порожню послідовність• Sequence::Sequence(size_t capacity):• _size(0),_seqArray(capacity)• {• return;• }; • // Деструктору поки що роботи немає. Чому?• Sequence::~Sequence()• {• return;• };

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

28

Делегування індексувань

• double & Sequence::operator[] (size_t index) const• {• if (empty())• throw BadSeq(“Empty sequence");• if (index>_size)• throw BadSeq (“Non existing element");• // Делегування доступу за індексом• return _seqArray[index];• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

29

Долучення до послідовності

• Sequence& Sequence::insert(double elem, size_t index)

• {• // Замовчуване значення індексу: дописати в

кінець• if (_size < index)• index=_size;•

• // Контейнер переповнено• if( _size + 1 > capacity())• throw BadSeq(“No more space");• _size++;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

30

Долучення до послідовності

• // Зсуваємо залишок послідовності праворуч• for (size_t i =_size-1; i > index; i--)• _seqArray[i]= _seqArray[i-1];

• // Заносимо новий елемент• _seqArray [index] = elem;• return *this;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

31

Необмежена послідовність

Можливість замінити менший контейнер більшим за домогою закритого методу enlarge() досягається за рахунок агрегування масиву указником

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

32

Збільшення контейнера

• void Sequence :: enlarge (int times)• {• Array *newAr=new

Array(times*_seqBlock+capacity());• if (newAr == 0) throw (“No more space");• assert(newArray != 0);• for (size_t i=0; i<_size; i++)• (*newAr)[i] = (*_seqArray)[i];• delete _seqArray;• _seqArray = newArray;• return;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

33

Вправа

Спроектувати послідовність на базі масиву, в якій можна буде зберігати об'єкти без попереднього виклику конструкторів без параметрів для заповнення всього масиву

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

34

Повторення

Два способи організації циклу над масивом• const int n=4;• int a[n];• // цикл за індексом• for (int i=0; i<n; ++i)• a[i]=i;• // цикл за ітератором• int *pcurrent = a;• int *const pend = a + n;• while (pcurrent!=pend)• cout<<*(pcurrent++)<<endl;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

35

Ітератори

Доповнимо послідовність трьома указниками

• private:• size_t _size;• Array * _seqArray;• // Указник поточного елементу• mutable double * _current;• // Указник початку послідовності• double * _start;• // Указник кінця послідовності• double * _end;

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

36

Ітератори

І чотирма методами

• // Почати ітерацію• void start() const { _current = _start;}• // Зробити наступний крок• void next() const { _current++;}• // Перевірити на закінчення• bool stop() const { return (_current == _end);}• // Взяти поточний елемент• const double& getElem() const { return

*_current;}

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

37

Застосування ітераторів

• ostream& operator<<(ostream &os, const Sequence& seq)

• {• seq.start();• while(!seq.stop())• {• cout<<chr<<seq.getElem()<<‘ ‘;• seq.next();• }• cout<<endl;• return os;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

38

Вправа

1. Побудувати контейнер послідовного доступу List у вигляді списку

2. Визначити ітератори так, щоб програми користувачів не залежали від типу контейнера

• ostream& operator<<(ostream &os, const List& seq)• {• seq.start();• while(!seq.stop())• {• cout<<chr<<seq.getElem()<<‘ ‘;• seq.next();• }• cout<<endl;• return os;• }

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

39

Обмежений стек на базі масиву

• class Stack• {• public:• explicit Stack(size_t size = _stackBlock);• ~Stack();• bool empty() const;• bool full() const;• size_t capacity() const;• const double top() const;• void pop();• void push(const double value);

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

40

Обмежений стек на базі масиву

• class BadStack;• private:• static const size_t _stackBlock;• // дно стеку• static const size_t _bos; • // верхівка стеку • size_t _top;• Array stackArray;• Stack(const &Stack);• Stack& operator=(const Stack&);• };

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

41

Обмежена черга на базі масиву

• class Queue• {• public:• explicit Queue (size_t size = _queueBlock);• ~Stack();• bool empty() const;• bool full() const;• size_t capacity() const;• const double front() const;• void pop();• void put(const double value);

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

42

Обмежена черга на базі масиву

• class BadQueue;• private:• static const size_t _bos;• static const size_t _QueueBlock;• size_t _size;• size_t _front;• size_t _back;• Array _QueueArray;• size_t plus1(size_t);• };

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

43

Вправа

• Визначте клас двосторонньої черги на базі масиву

© Бублик В.В. Програмування-2. Об'єктне програмування. Контейнерні класи

44

Висновки

Залежно від специфіки задачі використовуються контейнери з прямим (масив, послідовність), послідовним (список) або регламентованим (стек, черга, дек) доступом

Ітератори дозволяють користуватися контейнерами, не вдаючись в деталі їх визначення