"Вызов виртуальной функции с использованием объекта всегда разрешается статически. Вы получаете динамическое разрешение только через указатель или ссылку."
Это предложение не столько описывает правило языка C ++, сколько разрешено использовать компиляторам ярлыков.
Вы звоните showFunction
прямо по именам объектов. Итак, предположим, что showFunction
были объявлены виртуальными. Компилятор знает точные типы объектов, называемые first
и second
: они никак не могут быть объектами какого-либо другого типа. Таким образом, хотя язык говорит, что любая переопределяющая функция должна вызываться first.showVolume()
и second.showVolume()
, нет никакого возможного способа, которым результатом будут какие-либо функции, отличные от тех, которые компилятор может найти немедленно, поэтому на самом деле не нужно помещать какие-либо код для определения, какую функцию вызывать в результирующей программе. Правильная функция Mainclass::showVolume()
(или Derivedclass::showVolume()
, если она существовала) может вызываться напрямую, что может быть несколько более эффективным.
Цитата не относится к вызову Volume()
внутри showVolume()
. Поскольку Volume
называет нестатический член, Volume()
означает то же самое, что и this->Volume()
. this
- указатель, который может указывать или не указывать на объект, полный тип которого соответствует типу Mainclass* const
указателя. Так что в этом случае компилятор должен выполнить динамическое разрешение, чтобы определить, какую функцию вызывать.
Но еще одна вещь, на которую следует обратить внимание: это правда, что вы можете получить динамическое разрешение только через указатель или ссылку, но это не так, вы всегда получаете динамическое разрешение через указатель или ссылку. Когда функция называется «квалифицированным идентификатором» с использованием токена ::
, язык говорит, что вызываемая функция определяется статически, а переопределения игнорируются. Например, если ваш код в showVolume()
изменился на использование Mainclass::Volume()
или this->Mainclass::Volume()
, вы увидите, что он никогда не вызывает Derivedclass::Volume
.