Вывод ближе к правильному с virtual
и неверному с ним (если вы действительно этого не хотели).Приведение не меняет тип объектов, а только тип указателей.Они по-прежнему имеют тип Super
, и поэтому должен выполняться Super::showName
.
Приведение одного типа указателя к другому типу указателя не меняет тип объекта, на который указывает.Как это могло?Весь смысл виртуальных функций в том, чтобы иметь возможность вызывать методы для «общих» указателей и получать правильный метод производного класса.
Классический пример того, почему вы используете виртуальные функции, предназначен для музыкантов.У вас может быть функция, которая заставляет весь оркестр играть, вызывая метод Play
на каждом пройденном им Musician *
.Для Pianist
, который должен вызывать Pianist::Play
.
Обычно компилятор выясняет, какую функцию вызывать во время компиляции - раннее связывание.Единственная информация, которую должен знать компилятор, - это тип указателя.Ключевое слово virtual
заставляет привязку происходить поздно, во время выполнения, когда известен фактический тип члена класса.
Кстати, вы все равно можете вызывать метод базового класса, используя область действияпереопределения.Например, o1->Super::showName();
.
Фактически результат, который вы называете «правильным», катастрофичен.Запуск Special1::showName()
с указателем this
, указывающим на объект, который не относится к типу Special1
(или к чему-то производному от него), является неопределенным поведением и может легко привести к падению.