Для чого потрібен поліморфізм? Чи можна обійтися без нього?



+2 +/-

Питання пов'язаний з програмуванням.

Профіль користувача Corriann Запитав: Corriann  (рейтинг 23803) Категорія: Інтернет

Відповідей: 2

3 +/-
Найкраща відповідь

Поліморфізм - це техніка використання механізму пізнього зв'язування і успадкування.

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

Ну наприклад, ти пишеш гру в якій є город і різні види овочів - моркви, капусти і т.п. Юзер буде садити ці овочі в довільному порядку, ти не знаєш порядок на етапі написання програми, тому ти не можеш написати щось типу:

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 (). Програмісту тепер не треба паритися з цим, функція потрібного типу буде посдавлена ​​автоматично під час виконання.

Відповів на питання: Beady  
0 +/-

Можна без нього обійтися. Але навіщо? Поліморфізм дає можливість створювати однойменні функції, які відрізняються тільки типом (і / або кількістю) параметрів. Наприклад, є функція, яка поверне максимум з трьох чисел. Можна використовувати шаблон і застосувати функцію до будь-якого типу даних, а можна створити функції з сигнатурами:

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;

Відповів на питання: Bichord