Бублик Володимир ВасильовичПрограмування - 2 Лекція 10. Ієрархічне програмування. Поліморфізм Лекції для студентів 2 курсу
2.
Challenges ієрархійРізні реалізації одного й того ж класу ( StackAggregatingArray , StackDerivedFromArray , StackOnList) Розширення / спеціалізація класів ( DoubleList, CyclicList) Mixin (підмішування) : поєднання кількох функціональностей у одному класі ( PeekBack , Iterated)
Спеціалізація Як допрямокутника, так і ромба можна застосувати поведінку паралелограма 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 ; };
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) {}; };
Неоднозначність і неузгодженість Square sq(10); // Помилка: компілятор не знає, // з якого паралелограма брати дані sq.width(); // Помилка: заміна атрибуту в одному з базових об'єктів // з наступним використанням іншого базового об'єкту sq.Rectangle::width() = 20; sq.Rectangle::height() = 20; cout<<sq.Rhombus::area();
Віртуальне успадкування Відмінимовиклик конструктора в базових класах змішування Конструктор прямокутника (ромба) викличе конструктор паралелограма лише за умови, що його раніше не викликав конструктор квадрату class Rectangle : virtual public Parallelogram; class Rhombus : virtual public Parallelogram; class Square : public Rectangle, public Rhombus;
Приклад // Спочаткупаралелограм, потім прямокутник 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 ; }
Доповнений ромб 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); // паралелограм
25.
Приклад (хочемо) //Очікуваний результат 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 ) Непрямий виклик поширюється лише на спеціально позначені функції
Доповнений ромб 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.
Абстрактний клас Відсутністьреалізації класної функції позначається нулем Абстрактним називається клас, у якого відсутня реалізація хоча б однієї функції Використовуються для позначення спільного інтерфейсу класів, що допускають різні реалізації Об'єкт абстрактного класу створити не можна (чому?)
Зауваження Абстрактний класповинен завжди мати (порожній) віртуальний деструктор Перевірте, що станеться, якщо Деструктор не матиме реалізації Деструктор не буде віртуальним
З'єднання інтерфейсів 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 )