[БЕЗ_ЗВУКА] Теперь давайте рассмотрим различные свойства методов, помеченных ключевым словом virtual. В языке C++ для таких методов есть специальное название. Такие методы называются виртуальными. Во-первых, давайте попробуем понять, есть ли разница между виртуальными методами в базовом классе и обычными. Для этого давайте добавим новый класс, который унаследуем от класса Animal. Пусть это будет класс Horse – лошадь. [БЕЗ_ЗВУКА] И пусть этот класс будет отличаться от всех предыдущих тем, что мы не объявим в нем метод Sound. [БЕЗ_ЗВУКА] [БЕЗ_ЗВУКА] Теперь соберем программу и посмотрим, что у нас получится. [БЕЗ_ЗВУКА] Мы видим, что для лошади не вывелось никакой информации о том, какой звук она издает. Давайте теперь посмотрим, какой же метод Sound на самом деле для лошади вызывается. То есть программа собирается, какой-то метод вызывается, но какой именно? Разумно предположить, что вызывается метод Sound из базового класса. Давайте убедимся в этом. Пусть по умолчанию в базовом классе метод Sound говорит нам о том, что мы не знаем, какой звук издает животное. [БЕЗ_ЗВУКА] Давайте соберем и проверим нашу гипотезу. [БЕЗ_ЗВУКА] Да, действительно, все так. Лошадь не издала никакого звука. В этом смысле виртуальные методы ничем не отличаются от обычных методов базового класса, то есть в классах-потомках, если такой метод не объявлен, то будет вызван метод из базового класса. Теперь давайте рассмотрим другое полезное свойство виртуальных методов. Давайте предположим, что мы хотим сделать так, чтобы определенный виртуальный метод, объявленный в базовом классе, по-своему реализовывался в каждом классе-потомке. Но на данный момент класс Horse этому условию не удовлетворяет, в нем не объявлен метод Sound, и лошадь, получается, не издает никаких звуков. Такая ситуация может получиться, например, когда мы просто забыли реализовать этот метод, хотя программа может ожидать, что он должен быть обязательно реализован. И как мы видим, компилятор нам не говорит ничего о том, что этого метода нет, он просто берет метод из базового класса. Как бы мы могли достигнуть желаемого нами результата, то есть потребовать от всех классов-потомков обязательной реализации? Это можно добиться следующим синтаксисом. Мы убираем реализацию виртуального метода в базовом классе и дописываем такое выражение: мы пишем, что виртуальный метод равен 0. На самом деле данное выражение, данный синтаксис никак не связан с оператором присваивания, а также с нулем. Это просто формальный синтаксис, для которого в языке C++ нет никакого ключевого слова. Он обозначает следующее: он говорит компилятору о том, что виртуальный метод Sound является абстрактным, то есть или чисто виртуальным. Что это означает? Это означает, что как раз мы теперь требуем в каждом классе-потомке его обязательной реализации. Давайте попробуем собрать нашу программу и посмотрим, что же нам скажет компилятор. Действительно, теперь нам компилятор говорит о том, что у нас переменная H, которая объявлена типа Horse, имеет абстрактный тип, как раз указан класс Horse. Что означает «абстрактный тип»? Абстрактными типами, в данном случае классами называются те классы, у которых есть абстрактные методы, и для них нет реализации. В нашем случае это именно так. То есть у класса Horse нет реализации абстрактного метода Sound, таким образом класс Horse считается абстрактным. Также абстрактным считается базовый класс Animal. И, как нам говорит компилятор, мы не можем создавать объекты абстрактных классов. Таким образом, используя синтаксис абстрактных виртуальных методов, мы можем добиться того, что для каждого такого виртуального метода в классах-потомках у нас будет обязательно требоваться реализация.