Виртуальные функции реализуют полиморфизм.Я не знаю Obj-C, поэтому я не могу сравнить оба, но мотивирующий вариант использования - то, что вы можете использовать производные объекты вместо базовых объектов, и код будет работать.Если у вас есть скомпилированная и рабочая функция foo
, которая работает со ссылкой на base
, вам не нужно изменять ее, чтобы она работала с экземпляром derived
.
. Вы можете сделать это (при условии, чтоу вас была информация о типе времени выполнения), получив реальный тип аргумента и затем отправив его непосредственно в соответствующую функцию с переключателем шорт, но для этого потребуется либо вручную изменить переключатель для каждого нового типа (высокая стоимость обслуживания), либо иметь отражение (недоступно в C ++) для получения указателя на метод.Даже тогда, после получения указателя на метод, вам придется вызывать его, который так же дорог, как и виртуальный вызов.
Что касается стоимости, связанной с виртуальным вызовом, в основном (во всех реализациях с таблицей виртуальных методов)) вызов виртуальной функции foo
, примененной к объекту o
: o.foo()
переводится в o.vptr[ 3 ]()
, где 3
- это позиция foo
в виртуальной таблице, и это постоянная времени компиляции,По сути, это двойное косвенное указание:
Из объекта o
получить указатель на vtable, проиндексировать эту таблицу, получить указатель на функцию, а затем вызвать.Дополнительные затраты по сравнению с прямым неполиморфным вызовом - это просто поиск по таблице.(На самом деле могут быть и другие скрытые затраты при использовании множественного наследования, поскольку может потребоваться смещение неявного указателя this
), но стоимость виртуальной отправки очень мала.