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