Вопрос связан с программированием.
Вопрос связан с программированием.
Полиморфизм - это техника использования механизма позднего связывания и наследования.
Позднее связывание означает, что выбор конкретного типа переменной происходит во время работы программы, а не задается программистом явно.
Ну например, ты пишешь игру в которой есть огород и различные виды овощей - морковки, капусты и т.п. Юзер будет садить эти овощи в произвольном порядке, ты не знаешь порядок на этапе написания программы, поэтому ты не можешь написать что-то типа:
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; }
}
При таком раскладе, наш огород должен содержать список овощей (абстрактных):
vector
при этом в С++ для использования позднего связывания надо применять указатели (или умные указатели если не хотим мучиться с утечками памяти), а в Java и С#, например, все будет сделано автоматически, т.к. там повсеместно используется идиома PIMPL (там всегда везде умные указатели).
Допустим, юзер перетащит морковку в свой огород. При этом будет создана новая морковка (каким-либо образом - я привел пример с явным вызовом конструктора, но это могло бы быть и что то типа шаблона Prototype {при этом не было бы указано что это морковка даже}) и добавлена в список овощей.
Fruit *obj = new Carrot();
fruits->push_back(obj);
Затем, в этот список могли бы добавляться в хаотичном порядке другие овощи, а какой-либо код с некоторой периодичностью выполнял рост этих овощей:
for(i = 0; i < 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;
Добавить комментарий