Основная причина заключается в том, что сохранение vtable в качестве детали реализации позволяет любой конкретной реализации оптимизировать его по своему усмотрению; это означает, что оно может, например, обрезать или даже полностью исключить vtable, если это может доказать, что нет виртуальных вызовов для данного метода (или всех методов). Или он может заменить диспетчер vtable с проверкой типа if-else, если, например, он видит, что существует только несколько альтернатив (это может быть выгодным, потому что в этом случае будет работать предсказание ветвлений, но не с vtables, а также потому, что в противном случае могут быть добавлены ветви else-else). Он может переупорядочить методы в таблице vtable, так что наиболее часто называемые ранее или такие, что те, которые обычно называются один за другим, заполняют соседние слоты в таблице vtable, чтобы воспользоваться кешированием. И так далее. Разумеется, все эти реализации также сделают vtable-макет совершенно непредсказуемым и, следовательно, бесполезным, если он будет представлен (по языковой спецификации) для реализации.
Кроме того, vtables не так просты, как кажется. Например, компиляторам часто приходится генерировать thunks для фиксации указателя this
для таких виртуальных наследований или множественного наследования в сочетании с ковариантными типами возврата. Это опять-таки то, что не имеет «единственного наилучшего способа» для этого (поэтому разные компиляторы делают это по-другому), и стандартизация этого будет эффективно требовать определенного решения.
Это говорит о том, что «переключение vtable» - потенциально полезный метод, если он представлен как конструкция более высокого уровня (так что оптимизация по-прежнему возможна). Например, см. UnrealScript, который позволяет определить несколько states для класса (по умолчанию, другое имя) и переопределить некоторые методы в названных состояниях. Производные классы могут переопределять больше методов в существующих состояниях или добавлять свои собственные состояния и переопределять их. Кроме того, состояния могут распространять другие состояния (поэтому, если метод не переопределяется для определенного состояния, он возвращается к «родительскому» состоянию и так далее, пока цепочка не достигнет состояния по умолчанию). Для актерского моделирования (в сущности, это игры) все это имеет большой смысл, поэтому UnrealScript имеет его. И очевидный эффективный механизм реализации для всего этого - переключение vtable, причем каждое состояние имеет отдельный vtable.
Я уверен, что возиться с vtable будет * не * сделать код более читаемым/безопасным/надежным. – Bombe
Если бы была поддержка языка для этого, я бы не стал считать это «беспорядочным». Это будет понятная и широко используемая практика программирования. –
Да, но нет, так что ... –