10 Polymorphism

770 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
770
On SlideShare
0
From Embeds
0
Number of Embeds
11
Actions
Shares
0
Downloads
5
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

10 Polymorphism

  1. 1. Бублик Володимир Васильович Програмування - 2 Лекція 10. Ієрархічне програмування. Поліморфізм Лекції для студентів 2 курсу
  2. 2. Challenges ієрархій <ul><li>Різні реалізації одного й того ж класу ( StackAggregatingArray , StackDerivedFromArray , StackOnList) </li></ul><ul><li>Розширення / спеціалізація класів ( DoubleList, CyclicList) </li></ul><ul><li>Mixin (підмішування) : поєднання кількох функціональностей у одному класі ( PeekBack , Iterated) </li></ul>
  3. 3. Спеціалізація <ul><li>class Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>protected : </li></ul><ul><li>double _ height; </li></ul><ul><li>double _ width; </li></ul><ul><li>double _ angle; </li></ul><ul><li>public : </li></ul><ul><li>Parallelogram ( double h, double w, double a); </li></ul><ul><li>double area() const ; </li></ul><ul><li>double height() const ; </li></ul><ul><li>double width() const ; </li></ul><ul><li>double angle() const ; </li></ul><ul><li>}; </li></ul>
  4. 4. Спеціалізація <ul><li>Ромб і прямокутник служать прикладами (спеціалізаціями ) паралелограма </li></ul><ul><li>class Rhombus: public Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>Rhombus ( double h, double a) : </li></ul><ul><li>Parallelogram (h, h, a){ }; </li></ul><ul><li>}; </li></ul>
  5. 5. Спеціалізація <ul><li>class Rectangle: public Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>static const double pi = 3.1415926535897932; </li></ul><ul><li>Rectangle ( double h, double w) : </li></ul><ul><li>Parallelogram (h, w, pi/2){ }; </li></ul><ul><li>double area() double </li></ul><ul><li>{ </li></ul><ul><li>return _height * _ width; </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  6. 6. Спеціалізація
  7. 7. Спеціалізація <ul><li>Як до прямокутника, так і ромба можна застосувати поведінку паралелограма </li></ul><ul><li>Rhombus rh(10, pi/4); </li></ul><ul><li>rh.area(); rh.height(); rh.width(); rh.angle(); </li></ul><ul><li>Rectangle rec(10,20); </li></ul><ul><li>// власна поведінка </li></ul><ul><li>rec.area(); </li></ul><ul><li>// успадкована поведінка </li></ul><ul><li>Parallelogram :: rec.area(); </li></ul><ul><li>rec.height(); rec.width(); rec.angle(); </li></ul>
  8. 8. Управління доступом <ul><li>Можна закрити доступ до функції базового класу </li></ul><ul><li>class Rectangle: public Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>using Parallelogram ::area(); </li></ul><ul><li>public : </li></ul><ul><li>static const double pi = 3.1415926535897932; </li></ul><ul><li>Rectangle ( double h, double w) : </li></ul><ul><li>Parallelogram (h, w, pi/2){ }; </li></ul><ul><li>double area() double ; </li></ul><ul><li>}; </li></ul>
  9. 9. Mixin (змішування) : кратне успадкування <ul><li>Хижак </li></ul><ul><li>class Predator </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>string _name; </li></ul><ul><li>string _favoritePray; </li></ul><ul><li>public : </li></ul><ul><li>Predator (string name, pray); </li></ul><ul><li>}; </li></ul>
  10. 10. Mixin: кратне успадкування <ul><li>Домашній улюбленець </li></ul><ul><li>class Pet </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>string _name; </li></ul><ul><li>string _favoriteToy; </li></ul><ul><li>public : </li></ul><ul><li>Pet (string name, string toy); </li></ul><ul><li>}; </li></ul>
  11. 11. Mixin: кратне успадкування <ul><li>class Cat: public Predator, public Pet </li></ul><ul><li>{ </li></ul><ul><li>private : </li></ul><ul><li>static unsigned int _freeID; </li></ul><ul><li>unsigned int _myCatID; </li></ul><ul><li>public : </li></ul><ul><li>Cat (string name, string toy, string prey): </li></ul><ul><li>_myCatID (_freeID++), </li></ul><ul><li>Predator (name, prey), Pet (name, toy){ }; </li></ul><ul><li>}; </li></ul>
  12. 12. Mixin: кратне успадкування <ul><li>class Cat: public Predator, p ublic Pet </li></ul>
  13. 13. Consistency (узгодженість) <ul><li>Хто слідкуватиме за узгодженістю імен в базових об'єктах? </li></ul><ul><li>const string& Predator :: rename (string newname) </li></ul><ul><li>{ </li></ul><ul><li>return name = newname; </li></ul><ul><li>} </li></ul><ul><li>void cat::show() const { </li></ul><ul><li>cout<<Predator::name<<“ aka ”<<Pet::name; </li></ul><ul><li>} </li></ul>
  14. 14. Спеціалізація + змішування: спільний базовий клас <ul><li>Скільки паралелограмів міститься в одному квадраті? </li></ul><ul><li>class Square : public Rectangle, public Rhombus </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>Square ( double side ) : </li></ul><ul><li>Rectangle( side, side ), </li></ul><ul><li>Rhombus (side, pi/2) {}; </li></ul><ul><li>}; </li></ul>
  15. 15. Спільний базовий клас : помилка
  16. 16. Неоднозначність і неузгодженість <ul><li>Square sq(10); </li></ul><ul><li>// Помилка: компілятор не знає, </li></ul><ul><li>// з якого паралелограма брати дані </li></ul><ul><li>sq.width(); </li></ul><ul><li>// Помилка: заміна атрибуту в одному з базових об'єктів </li></ul><ul><li>// з наступним використанням іншого базового об'єкту </li></ul><ul><li>sq.Rectangle::width() = 20; </li></ul><ul><li>sq.Rectangle::height() = 20; </li></ul><ul><li>cout<<sq.Rhombus::area(); </li></ul>
  17. 17. Спільний базовий клас: запит
  18. 18. Віртуальне успадкування <ul><li>Відмінимо виклик конструктора в базових класах змішування </li></ul><ul><li>Конструктор прямокутника (ромба) викличе конструктор паралелограма лише за умови, що його раніше не викликав конструктор квадрату </li></ul><ul><li>class Rectangle : virtual public Parallelogram; </li></ul><ul><li>class Rhombus : virtual public Parallelogram; </li></ul><ul><li>class Square : public Rectangle, public Rhombus; </li></ul>
  19. 19. Ініціалізація <ul><li>Parallelogram::Parallelogram( double h, double w, double a): </li></ul><ul><li>_height (h), _width (w), _angle (a) {}; </li></ul><ul><li>Rectangle::Rectangle ( double h, double w): </li></ul><ul><li>Parallelogram (h, w, pi/2) {}; </li></ul><ul><li>Rhombus::Rhombus( double side, double a ): </li></ul><ul><li>Parallelogram (side, side, a) {}; </li></ul><ul><li>Square::Square ( double side ) : </li></ul><ul><li>Rectangle( side, side ), </li></ul><ul><li>Rhombus (side, pi/2 ) , </li></ul><ul><li>Parallelogram( side, side, pi/2) {}; </li></ul>
  20. 20. Приклад <ul><li>// Спочатку паралелограм, потім прямокутник </li></ul><ul><li>Rectangle rec(10, 20); </li></ul><ul><li>// Спочатку паралелограм, потім ромб </li></ul><ul><li>Rhombus rh(10, pi/3); </li></ul><ul><li>// Конструктор паралелограма викликається </li></ul><ul><li>// конструктором квадрата, прямокутник і ромб </li></ul><ul><li>// використовують вже наявний паралелограм </li></ul><ul><li>Square sq(10); </li></ul>
  21. 21. Контроль типів <ul><li>Простий обробник фігур </li></ul><ul><li>void processFigure ( const Parallelogram & figure) </li></ul><ul><li>{ </li></ul><ul><li>cout<<figure.whatAmI(); </li></ul><ul><li>cout<<figure.area(); </li></ul><ul><li>cout<<figure.perimeter(); </li></ul><ul><li>return ; </li></ul><ul><li>} </li></ul>
  22. 22. Доповнений паралелограм <ul><li>class Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>protected : </li></ul><ul><li>double _ height, _ width, _ angle; </li></ul><ul><li>public : </li></ul><ul><li>Parallelogram ( double h, double w, double a); </li></ul><ul><li>double area() const ; </li></ul><ul><li>const string& whoAmI() const </li></ul><ul><li>{ </li></ul><ul><li>return string(“Parallelogram”); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  23. 23. Доповнений ромб <ul><li>class Rhombus: public Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>Rhombus ( double h, double a) : </li></ul><ul><li>Parallelogram (h, h, a){ }; </li></ul><ul><li>const string& whoAmI() const </li></ul><ul><li>{ </li></ul><ul><li>return string(“Rhombus”); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>Те ж саме для прямокутника і квадрата </li></ul>
  24. 24. Приклад (маємо) <ul><li>// Очікуваний результат </li></ul><ul><li>Parallelogram par(20, 30, pi/6); </li></ul><ul><li>processFigure (par); </li></ul><ul><li>// паралелограм </li></ul><ul><li>// Несподіваний результат </li></ul><ul><li>Rhombus rh(10, pi/3); </li></ul><ul><li>processFigure (rh); </li></ul><ul><li>// паралелограм </li></ul>
  25. 25. Приклад (хочемо) <ul><li>// Очікуваний результат </li></ul><ul><li>Parallelogram par(20, 30, pi/6); </li></ul><ul><li>processFigure (par); </li></ul><ul><li>// паралелограм </li></ul><ul><li>Rhombus rh(10, pi/3); </li></ul><ul><li>processFigure (rh); </li></ul><ul><li>// ромб </li></ul>
  26. 26. Повторення <ul><li>Статичний поліморфізм: </li></ul><ul><li>Виклик функції за указником </li></ul><ul><li>Simpson (a, b, eps, pf); </li></ul><ul><li>Вибір функції за типами параметрі в </li></ul><ul><li>Complex(1,2)+Complex(3,4); </li></ul><ul><li>string(“First”)+string(“second”); </li></ul><ul><li>(Динамічний) поліморфізм: вибрати функцію залежно від типу значення імені об'єкта </li></ul><ul><li>figure.whatAmI(); </li></ul>
  27. 27. Ієрархія типів <ul><li>Об'єкт може належати багатьом типам </li></ul><ul><li>Квадрат одночасно є прямокутником, ромбом і паралелограмом </li></ul><ul><li>Прямокутник і ромб одночасно є паралелограмами </li></ul><ul><li>Ім'я паралелограма здатне приймати значення довільного допустимого типу </li></ul><ul><li>Параметр Parallelogram & par може прийняти паралелограм, прямокутник, ромб або квадрат </li></ul><ul><li>Указник Parallelogram * ppar може показувати на кожен з них, наприклад, Parallelogram * ppar = new Squre(10); </li></ul>
  28. 28. Віртуальні функції <ul><li>Об'єкти володіють даними-членами класу і розділяють функції-члени класу </li></ul><ul><li>Прямий виклик класної функції (поки що) </li></ul><ul><li>Triangle((0,0), (0,1), (1,0)).sideA(); </li></ul><ul><li>Непрямий виклик віртуальної функції </li></ul><ul><li>перевірити яке саме значення має par </li></ul><ul><li>взяти функцію (з таблиці віртуальних функцій vtab ) </li></ul><ul><li>Непрямий виклик поширюється лише на спеціально позначені функції </li></ul>
  29. 29. Доповнений паралелограм <ul><li>class Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>protected : </li></ul><ul><li>double _ height, _ width, _ angle; </li></ul><ul><li>public : </li></ul><ul><li>Parallelogram ( double h, double w, double a); </li></ul><ul><li>virtual double area() const ; </li></ul><ul><li> virtual const string& whoAmI() const </li></ul><ul><li>{ </li></ul><ul><li>return string(“Parallelogram”); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul>
  30. 30. Доповнений ромб <ul><li>class Rhombus: public Parallelogram </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>Rhombus ( double h, double a) : </li></ul><ul><li>Parallelogram (h, h, a){ }; </li></ul><ul><li>virtual const string& whoAmI() const </li></ul><ul><li>{ </li></ul><ul><li>return string(“Rhombus”); </li></ul><ul><li>} </li></ul><ul><li>}; </li></ul><ul><li>Те ж саме для прямокутника і квадрата </li></ul>
  31. 31. Поліморфізм <ul><li>Можливість динамічно використовувати для роботи з похідними класами інтерфейс базового класу </li></ul><ul><li>// Поліморфізм не використовується </li></ul><ul><li>Rectangle rec(10, 20); </li></ul><ul><li>rec.whoAmI(); </li></ul><ul><li>// Поліморфізм </li></ul><ul><li>Parallelogram * par = container.getParallelogram(); </li></ul><ul><li>par->whoAmI(); </li></ul>
  32. 32. Забутливе присвоєння <ul><li>Поліморфізм здатен проявитися лише при застосуванні указника базового класу або передачі базового класу відсилкою (в тому числі сталою) </li></ul><ul><li>Присвоєння об'єкту похідного класу на місце, призначене для базового об'єкту, призведе до забування додаткових властивостей похідного типу і його зведення до базового </li></ul><ul><li>Parallelogram par = Rectangle(10, 20); </li></ul>
  33. 33. Інтерфейс <ul><li>Можливість динамічно використовувати для роботи з похідними класами інтерфейс (неіснуючого) абстрактного базового класу </li></ul><ul><li>class Stack </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>virtual ~Stack () {} ; </li></ul><ul><li>virtual const Elem& top() const =0; </li></ul><ul><li>virtual void pop() =0; </li></ul><ul><li>virtual void push( const Elem & value) =0; </li></ul><ul><li>}; </li></ul>
  34. 34. Абстрактний клас <ul><li>Відсутність реалізації класної функції позначається нулем </li></ul><ul><li>Абстрактним називається клас, у якого відсутня реалізація хоча б однієї функції </li></ul><ul><li>Використовуються для позначення спільного інтерфейсу класів, що допускають різні реалізації </li></ul><ul><li>Об'єкт абстрактного класу створити не можна (чому?) </li></ul>
  35. 35. Успадкування інтерфейсу <ul><li>class StackAggregatingArray: public Stack </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>StackAggregatingArray ( size_t ); </li></ul><ul><li>~StackAggregatingArray (); </li></ul><ul><li>const Elem& top() const; </li></ul><ul><li>void pop() ; </li></ul><ul><li>void push( const Elem & value) ; </li></ul><ul><li>private : </li></ul><ul><li>static const size_t _ bos; </li></ul><ul><li>size_t _top; </li></ul><ul><li>Array _array ; </li></ul><ul><li>}; </li></ul>
  36. 36. Успадкування інтерфейсу <ul><li>class StackAggregatingArray: public Stack </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>StackAggregatingArray ( size_t ); </li></ul><ul><li>virtual ~StackAggregatingArray (); </li></ul><ul><li>virtual const Elem& top() const; </li></ul><ul><li>virtual void pop() ; </li></ul><ul><li>virtual void push( const Elem & value) ; </li></ul><ul><li>private : </li></ul><ul><li>static const size_t _ bos; </li></ul><ul><li>size_t _top; </li></ul><ul><li>Array _stackArray ; </li></ul><ul><li>}; </li></ul>
  37. 37. Діаграма реалізацій інтерфейсу
  38. 38. Зауваження <ul><li>Абстрактний клас повинен завжди мати (порожній) віртуальний деструктор </li></ul><ul><li>Перевірте, що станеться, якщо </li></ul><ul><li>Деструктор не матиме реалізації </li></ul><ul><li>Деструктор не буде віртуальним </li></ul>
  39. 39. Виклик віртуальних функцій <ul><li>void process(Stack & stack) </li></ul><ul><li>{ </li></ul><ul><li>cout<<stack.top(); </li></ul><ul><li>…………… </li></ul><ul><li>}; </li></ul><ul><li>StackDerivedFromArray sdfa; </li></ul><ul><li>process(sdfa); </li></ul><ul><li>StackAggregatingArray saga; </li></ul><ul><li>process(saga); </li></ul>
  40. 40. Вправа <ul><li>Визначити і реалізувати абстрактний клас (інтерфейс) трикутника </li></ul>
  41. 41. З'єднання інтерфейсів <ul><li>class PeekBack </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>virtual bool peekback( size_t i, Elem& elem) c onst =0; </li></ul><ul><li>virtual ~PeekBack() { }; </li></ul><ul><li>}; </li></ul><ul><li>class PeekbackStack: virtual public Stack, public PeekBack </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>virtual bool peekback(size_t i, Elem& elem) const =0; </li></ul><ul><li>virtual ~PeekbackStack() { }; </li></ul><ul><li>}; </li></ul>
  42. 42. Реалізація з'єднаного інтерфейсу <ul><li>class Peek B ackStackAgregating Array : </li></ul><ul><li>// Успадкування інтерфейсу підглядань </li></ul><ul><li>public PeekbackStack, </li></ul><ul><li>// Реалізація інтерфейсу стеку </li></ul><ul><li>public StackAgregatingArray, </li></ul><ul><li>{ </li></ul><ul><li>public : </li></ul><ul><li>// Реалізації інтерфейсу підглядань </li></ul><ul><li>Peek B ackStackAgregating Array ( size_t size) ; </li></ul><ul><li>virtual ~AgregatingPeekbackStack() ; </li></ul><ul><li>virtual bool peekback(int i, Elem& elem) const ; </li></ul><ul><li>}; </li></ul>
  43. 43. Висновки <ul><li>Віртуальні функції служать для </li></ul><ul><li>Реалізації інтерфейсів </li></ul><ul><li>Заміщення ( overriding ) реалізації функції базового класу реалізацією, призначеною для підкласу </li></ul><ul><li>Поліморфізм приводить до того, що одне і те ж ім'я (указник) протягом виконання програми набуває значень в різних класах, але із спільним інтерфейсом </li></ul><ul><li>Порівняйте з довизначенням ( overloading ) </li></ul>

×