Питання пов'язаний з програмуванням.
Питання пов'язаний з програмуванням.
Поліморфізм - це техніка використання механізму пізнього зв'язування і успадкування.
Пізніше зв'язування означає, що вибір конкретного типу змінної відбувається під час роботи програми, а не задається програмістом явно.
Ну наприклад, ти пишеш гру в якій є город і різні види овочів - моркви, капусти і т.п. Юзер буде садити ці овочі в довільному порядку, ти не знаєш порядок на етапі написання програми, тому ти не можеш написати щось типу:
Carrot carrot_obj;
// ...
carrot_obj-> grow (); // Просиш конкретну морквину підрости
Є різні способи вивернутися і вирішити проблему в цій ситуації, але найлаконічніший з них - це поліморфізм.
Пізніше зв'язування виконує визначення конкретного типу (виду овоча) на етапі виконання, а на етапі компіляції ти повинен зв'язати всі види овочів з більш загальним типом. Тому поліморфізм - це спадкування + пізніше зв'язування. Найбільш загальний клас
повинен описувати інтерфейс для всіх наших овочів:
class Fruit {
protected:
int size;
public:
virtual int grow () = 0; // Метод змушує абстрактний овоч рости
};
Саме через цей інтерфейс при використанні поліморфізму ми звертаємося до конкретних класах овочів (вибір конкретного класу виконується автоматично {програмісту не треба для цього нічого робити} в залежності від типу об'єкта, який прихований за цим інтерфейсом:
class Carrot: public Fruit {
public:
int grow () {return ++ size; }
}
class Potato: public Fruit {
public:
int grow () {return size + = 2; }
}
При такому розкладі, наш город повинен містити список овочів (абстрактних):
vectorlt; Fruit *> fruits;
при цьому в С ++ для використання пізнього зв'язування треба застосовувати покажчики (або розумні покажчики якщо не хочемо мучитися з витоками пам'яті), а в Java і С #, наприклад, все буде зроблено автоматично, тому що там повсюдно використовується ідіома PIMPL (там завжди всюди розумні покажчики).
Припустимо, користувач перетягне морквину в свій город. При цьому буде створено нову морквина (будь-яким чином - я навів приклад з явним викликом конструктора, але це могло б бути і що то типу шаблону Prototype {при цьому не було б вказано що це морквина навіть}) і додана в список овочів.
Fruit * obj = new Carrot ();
fruits-> push_back (obj);
Потім, в цей список могли б додаватися в хаотичному порядку інші овочі, а якийсь код з певною періодичністю виконував зростання цих овочів:
for (i = 0; i lt; fruits.size (); ++ I) {
fruits [i] -> grow ();
}
При цьому якщо i-тий об'єкт масиву фруктів був створений як морквина, то буде виконуватися код Carrot :: grow (), а якщо як картопля - то Potato :: grow (). Програмісту тепер не треба паритися з цим, функція потрібного типу буде посдавлена автоматично під час виконання.
Можна без нього обійтися. Але навіщо? Поліморфізм дає можливість створювати однойменні функції, які відрізняються тільки типом (і / або кількістю) параметрів. Наприклад, є функція, яка поверне максимум з трьох чисел. Можна використовувати шаблон і застосувати функцію до будь-якого типу даних, а можна створити функції з сигнатурами:
int maxOf (int a, int b, int c)
{
..
}
float maxOf (float a, float b, float c)
{....}
double maxOf (double a, double b, double c)
{....}
і потім ці функції і смикати:
int x1, x2, x3, x4;
x4 = maxOf (x1, x2, x3);
double a1, a2, a3, a4;
a4 = maxOf (a1, a2, a3);
Зручно і красиво і голова не болить як функції обзивати, коли вони роблять одне і теж, але з різними типами даних.
У Delphi для тих же самих випадків треба використовувати ключове слово overload:
function maxOf (a, b, c: integer): integer; overload;
begin ..... end;
function maxOf (a, b, c: float): float; overload;
begin ..... end;
function maxOf (a, b, c: extended): extended; overload;
begin ..... end;
Залишити відповідь