Полиморфизм указывает, какую версию метода текущего объекта запустить.
Например, у вас есть несколько наследуемых классов, с разной реализацией одного и того же метода. То есть, у вас есть несколько разных методов с одинаковым именем (и сигнатурой), реализованных в разных классах. Какую версию метода вызвать? Это зависит от типа переменной, в которой находится объект.
Также с помощью полиморфизма можно поместить объекты разных классов в один массив с типом базового класса.
Создадим три класса с двумя методами - один виртуальный, а другой нет. Виртуальный метод переопределён (override) в классах-наследниках. Невиртуальный метод просто скрыт в наследниках новой реализацией (невиртуальные нельзя переопределять).
class Animal {
public void Info() { Console.WriteLine("Animal"); }
public virtual void Say() { Console.WriteLine("Nothing to say"); }
}
class Cat : Animal {
public void Info() { Console.WriteLine("Cat"); }
public override void Say() { Console.WriteLine("Meow"); }
}
class Dog : Animal {
public void Info() { Console.WriteLine("Dog"); }
public override void Say() { Console.WriteLine("Woof"); }
}
При создании объекта важно, в переменную какого типа объект будет записан:
Dog dog1 = new Dog();
Animal dog2 = new Dog();
// Не виртуальный метод - вызовется метод класса, указанного у переменной
dog1.Info(); // напишет Dog
dog2.Info(); // напишет Animal
// Виртуальный метод - вызовется метод класса, которого переменная реально имеет
dog1.Say(); // напишет Woof
dog2.Say(); // напишет Woof
А теперь частая ситуация, когда полиморфизм нужен - при итерации массива:
Animal[] animals = new Animal[10];
FillAnimals(animals); // заполним массив вперемешку собаками и кошками
foreach (var animal in animals) animal.Say(); // вызовется правильный метод
// У невиртуальных методов так сделать нельзя! Полиморфизм в действии
Наследование без виртуальных методов полезен только фиксацией интерфейса.
Вот весь код примера:
code.re/5ZC
Вставьте его
вот сюда и проверьте.
P.S. Написал код на C#, чтобы подчеркнуть разницу между виртуальными и невиртуальными методами. В Javascript все методы виртуальные (как и в php, например).
UPD. (спасибо
@Petroveg)
В языке C# (и других статически типизированных) обычно делают так - если метод в базовом классе записывается для всех потомков и оттуда будут использоваться напрямую, то он помечается обычным, невиртуальным. А если метод предназначен для того, чтобы в наследниках его переопределить, то необходимо его сделать виртуальным, чтобы при вызове метода компилятор выбрал нужную версию метода. То есть некоторые методы лучше делать виртуальными, а некоторые нет.
И ещё раз - виртуальность важна только в одном случае - если объект-наследник записан в переменную базового класса:
Animal animal = new Dog();
В javascript невиртуальных методов не бывает - динамическая основа этого языка ВСЕГДА автоматически вызывает именно последнюю версию метода, определяя конкретную по цепочке прототипов. Поэтому в Javascipt, по большому счёту, сильно думать о полиморфизме смысла нет - это только абстрактная концепция, не влияющая на сам код, а только на архитектуру.