Ответ
Динамическая диспетчеризация (dynamic dispatch) — самый медленный тип, поскольку определение вызываемого метода происходит во время выполнения программы (runtime), а не на этапе компиляции.
Почему он медленный:
- Поиск в таблице методов: Требуется обращение к таблице виртуальных методов (vtable) или аналогичной структуре для определения адреса реализации.
- Отсутствие оптимизаций компилятора: Компилятор не может применить ключевые оптимизации, такие как инлайнинг (подстановка кода функции) или девиртуализация.
- Проблемы с предсказанием ветвлений: Процессору сложно предсказать, какой код будет выполнен, что приводит к сбросам конвейера команд.
Пример на Swift (протокол):
protocol Drawable {
func draw()
}
struct Circle: Drawable {
func draw() { print("Рисую круг") }
}
struct Square: Drawable {
func draw() { print("Рисую квадрат") }
}
// Компилятор не знает точный тип `shape` во время компиляции
let shape: Drawable = Bool.random() ? Circle() : Square()
shape.draw() // Динамический вызов: поиск метода `draw` в runtime
Когда использовать: Для полиморфизма, когда тип объекта неизвестен на этапе компиляции (работа через протоколы или базовые классы).
Что использовать для производительности: Статическую диспетчеризацию (структуры, final-классы, generic-параметры), где вызов метода разрешается на этапе компиляции.