Поліморфізм та віртуальні функції


НазваПоліморфізм та віртуальні функції
Дата конвертації06.02.2013
Розмір445 b.
ТипПрезентации


Поліморфізм та віртуальні функції.

  • Похідні класи мають з базовим класом зв'язки двох видів. Перший з них полягає в тому, що екземпляри похідних класів використовують всі відкриті члени базового класу – зокрема методи базового класу.

  • class Base

  • { public:

  • void meth ()

  • {

  • cout << "In Base: meth() " << endl;

  • }

  • };

  • class SubBase : public Base

  • { // …

  • };

  • int main (void)

  • {

  • Base b; // екземпляр базового класу

  • SubBase sb; // екземпляр похідного класу

  • b.meth (); // виклик методу базового класу

  • sb.meth (); // виклик методу базового класу

  • return 0;

  • }


  • Другий вид зв'язку полягає в тому, що:

  • екземпляр базового класу можна створити як екземпляр похідного

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

  • посилання на базовий клас може посилатись на похідний;

  • вказівник на базовий клас може вказувати на похідний.

  • Всі ці операції виконуються без явного приведення типів і є реалізацією відношення «is-a».

  • int main (void) {

  • Base b;

  • SubBase sb;

  • // екземпляр базового класу створюється як похідний

  • Base bb = SubBase ();

  • // екземпляру базового класу присвоюється похідний

  • b = sb;

  • // посилання на базовий клас посилається на похідний

  • Base & bbb = sb;

  • // вказівник на базовий клас вказує на похідний

  • Base *p = &sb;

  • // sb = b; // таке присвоєння неможливе!

  • return 0;

  • }



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

  • class Base

  • { public:

  • void meth ()

  • { cout << "In Base: meth()" << endl; }

  • };

  • class SubBase : public Base

  • {

  • void meth_SubBase ()

  • { cout << "Власний метод похідного класу" << endl;}

  • };

  • int main (void)

  • {

  • Base b; // екземпляр базового класу

  • SubBase sb = b; // припустимо це можливим

  • b.meth (); // виклик методу базового класу

  • sb.meth_SubBase (); // в похідному класі метод відсутній

  • return 0;

  • }



  • Та обставина, що посилання та вказівники базового класу можуть вказувати на екземпляри похідних класів, приводить до низки цікавих можливостей – зокрема методи, які мають параметрами посилання або вказівник на базовий клас, можуть викликатись із аргументами-екземплярами похідних класів:

  • void fun (Base & b) // параметр – посилання на

  • // базовий клас

  • {

  • b.meth();

  • }

  • int main (void)

  • {

  • Base b;

  • SubBase sb;

  • fun (b); // такий виклик можливий

  • fun (sb); // і такий теж можливий

  • return 0;

  • }

  • Але в будь-якому разі, функція fun() викликатиме метод meth() базового класу.



  • Проте, можлива ситуація, коли успадковані методи похідних класів повинні поводити себе інакше, ніж методи базового класу. Така поведінка називається “поліморфною”. (Поліморфний – такий, що має багато форм). Реалізація поліморфного спадкування здійснюється одним із двох способів.

  • 1. Перевизначення методів базового класу у похідному класі (заміщення методів) :

  • class Base

  • { public:

  • void meth ()

  • { cout << "In Base: meth() " << endl; }

  • };

  • class SubBase : public Base

  • {

  • // цей метод перекриває відповідний метод базового класу

  • void meth ()

  • { cout << "In SubBase: meth() " << endl;}

  • };

  • int main (void) {

  • Base b; // екземпляр базового класу

  • SubBase sb; // екземпляр похідного класу

  • b.meth (); // виклик методу базового класу

  • sb.meth (); // виклик методу похідного класу

  • return 0;

  • }



  • В усіх попередніх прикладах зв'язування екземпляру із конкретним методом (функцією-членом класу) відбувалось на етапі компіляції (тобто ще до початку виконання програми). Ця процедура, як відомо, називається раннім зв'язуванням. Альтернативний спосіб – пізнє зв'язування (інколи – динамічне зв'язування, в С# - динамічний поліморфізм) дозволяє асоціювати об'єкт із методом вже під час виконання програми.

  • 2. Використання віртуальних методів . Пізнє зв'язування охоплює ряд функцій-членів (методів), які називаються віртуальними функціями. Віртуальна функція (virtual) оголошується в базовому класі і перевизначається у похідних класах. Сукупність класів, в яких визначається і перевизначається віртуальна функція, називається поліморфним кластером. У межах цього кластеру об'єкт пов'язується із конкретною віртуальною функцією-членом під час виконання програми. Звичайна функція-член також може бути перевизначена у похідному класі, як у попередньому прикладі. Проте без атрибуту virtual до неї буде застосоване лише раннє зв'язування.



Приклад.

  • class Base

  • {

  • public:

  • virtual void virt () // це віртуальний метод

  • {

  • cout << "In class Base" << endl;

  • }

  • };

  • class SubBase : public Base

  • {

  • public :

  • //віртуальний метод заміщається у похідному класі

  • //слово virtual у похідному класі – не обов’язкове

  • virtual void virt ()

  • {

  • cout << "In class SubBase" << endl;

  • }

  • };



  • Тепер, якщо визначити зовнішню функцію fun (Base & b), як у попередньому прикладі, то ми побачимо реалізацію пізнього зв'язування:

  • void fun (Base & b)

  • {

  • b.virt();

  • }

  • int main (void)

  • {

  • Base b;

  • SubBase sb;

  • fun (b); // виклик методу virt()базового класу

  • fun (sb);// виклик методу virt()похідного класу

  • return 0;

  • }

  • Рішення про те, який саме метод virt() базового чи похідного класу має бути викликаний у функції fun, приймається під час виконання програми – це пізнє звязування.



  • Віртуальні методи можуть перевантажуватись, як звичайні функції:

  • class Base

  • {

  • public:

  • virtual void virt () // віртуальний метод

  • { cout << "In class Base" << endl; }

  • virtual void virt (int i)// ще один вірт. метод

  • { cout << "In class Base " << i << endl; }

  • };

  • class SubBase : public Base

  • {

  • public :

  • virtual void virt ()

  • { cout << "In class SubBase" << endl; }

  • virtual void virt (int i)

  • { cout << "In class SubBase" << i << endl; } };



  • Слід зазначити, що використання пізнього зв'язування достатньо складний механізм, який вимагає суттєвих витрат пам'яті. Тому віртуальними слід робити лише такі функції, які дійсно будуть перевизначатись у похідних класах.

  • Зауваження. Конструктори не можуть бути віртуальними – адже похідний клас не спадкує конструктор базового. А от деструктор може бути віртуальним. Користь віртуального деструктора показує наступний приклад, висновком з якого може бути правило:

    • якщо клас не вимагає явного виконання деструктора, краще визначити віртуальний деструктор, навіть якщо йому не має чого робити.


Приклад.

  • class Base

  • {

  • public: // раніше визначені члени класу

  • char name [20];

  • virtual ~Base () // віртуальний деструктор

  • {cout << "Destructor Base" << name << endl;}

  • };

  • class SubBase : public Base

  • {

  • public : // раніше визначені члени класу

  • virtual ~SubBase () // віртуальний деструктор

  • {cout << "Destructor SubBase" << name << endl;}

  • };

  • int main (void)

  • {

  • Base *p = new SubBase ("Gibrid");

  • delete p;

  • return 0;

  • }



  • Повернемось ще раз до перевизначення функцій.

  • Якщо в похідному класі визначається метод, одноіменний з віртуальним методом базового класу, але з відмінною сигнатурою, він перекриває всі віртуальні методи базового класу. Це означає, що в похідному класі вони не доступні.

  • class Base

  • { public: // раніше визначені члени класу

  • virtual virt (); // віртуальний метод

  • };

  • class SubBase : public Base

  • { public : // раніше визначені члени класу

  • virt (int i); // метод - перекриває віртуальний

  • };

  • int main (void)

  • {

  • Base b = Base ("Base");

  • SubBase sb = SubBase ("SubBase");

  • sb (10); // припустимо

  • sb (); // помилка – метод базового класу недоступний

  • return 0;

  • }



Абстрактний базовий клас (ABC – Abstract Base Class).

  • Наразі нам відомі правила простого спадкування та більш складного поліморфного спадкування, яке включає використання віртуальних функцій. Наступний рівень складності – абстрактний базовий клас. Необхідність в ньому виникає, коли необхідно описати об'єкти, що мають східну природу, проте їх важко визначити як базовий та похідний класи. Наприклад, розглядаючи такі об'єкти, як прямокутник та ромб, неможливо встановити між ними відношення «Є» (“is-a”), хоча й очевидно, що вони мають багато спільного: наприклад, поняття площі, повороту на площині. У таких випадках необхідно виділити у об'єктів все спільне і створити клас, який буде базовим для них всіх. Якщо реалізація окремих функцій можлива лише на рівні похідних класів, у базовому їх визначають як чисто віртуальні функції (pure virtual function ). Екземпляри такого базового класу неможливо створити, сам клас називається абстрактним і використовується лише для створення похідних класів.



Приклад.

  • class Figure // клас абстрактний – він має чисто віртуальну функцію

  • { protected :

  • double x_cnt, y_cnt; // координати центру фігури

  • public:

  • Figure (double x=0, double y=0) : x_cnt (x), y_cnt (y) {}

  • // чисто віртуальна функція:

  • virtual double Square () const = 0;

  • };

  • class Rectangle : public Figure // похідний клас – прямокутник

  • { private :

  • double leng, width;

  • public :

  • Rectangle (double l=0,double w=0,double x=0,double y=0);

  • double Square () const { return leng*width; }

  • };

  • class Rhombus : public Figure // похідний клас – ромб

  • { private :

  • double len, angle;

  • public :

  • Rhombus (double l = 0,double a = 0,double x =0,double y =0);

  • double Square () const { return len*len*sin(angle); }

  • };



Схожі:

Поліморфізм та віртуальні функції iconІнтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу)
Віртуальні функції краще всього закрити похідні класи налагоджують власну реалізацію закритої, а значить невидимої клієнту, частини...
Поліморфізм та віртуальні функції iconПоняття про віртуальні захищені (приватні) мережі (vpn) Поняття про віртуальні захищені (приватні) мережі (vpn)
Об’єднання локальних мереж і окремих комп’ютерів через відкрите зовнішнє середовище передавання інформації в єдину віртуальну мережу,...
Поліморфізм та віртуальні функції iconІнформації в операційних системах, базах даних І мережах Лекції 20-21 Віртуальні приватні мережі vpn план Поняття про віртуальні захищені (приватні) мережі (vpn) Види віртуальних приватних мереж
Об’єднання локальних мереж і окремих комп’ютерів через відкрите зовнішнє середовище передавання інформації в єдину віртуальну мережу,...
Поліморфізм та віртуальні функції iconВказівники на функції в мові с ім’я функції є константним вказівником на перший
Адресу функції можна присвоїти вказівнику та використовувати його для звертання до функції
Поліморфізм та віртуальні функції iconТема : Властивості функції. Квадратична функція
Повторити властивості функції. Уміти визначати властивості функції по графіку. Закріпити побудову графіка квадратичної функції. Вдосконалювати...
Поліморфізм та віртуальні функції iconТригонометричні функції Властивості і графік функції у= tgx
Домогтися засвоєння учнями основних понять, пов'язаних з означенням функції у= tgx та її властивостям,відтворення властивостей функції,застосовувати...
Поліморфізм та віртуальні функції iconСформулюйте означення графіка функції
Ознайомити учнів із означенням лінійної функції та сформувати знання про графік та властивості лінійної функції; виробити первинні...
Поліморфізм та віртуальні функції iconФункції конкуренції у ринковій економіці – 3 функції Функції конкуренції у ринковій економіці – 3 функції
Теорія заснована на припущеннях щодо домінування у багатьох законах про конкуренцію
Поліморфізм та віртуальні функції iconПравила знаходження максимуму і мінімуму функції. Знаходження найбільшого і найменшого значення функції. Загальна схема дослідження функції та побудова її графіка

Поліморфізм та віртуальні функції iconОсобливості використання підпрограм-функцій План Функції: опис і правила звертання
В розділі команд функції обов'язково повинен бути оператор присвоювання, який надає імені функції значення результату

Додайте кнопку на своєму сайті:
dok.znaimo.com.ua


База даних захищена авторським правом ©dok.znaimo.com.ua 2013
звернутися до адміністрації
dok.znaimo.com.ua
Головна сторінка