Чтобы понять систему приведения, вам необходимо погрузиться в объектную модель.
Классическим представлением модели простой иерархии является ограничение: что если B
происходит от A
, тогда объект B
будет фактически содержать подобъект A
наряду со своими собственными атрибутами.
В этой модели downcasting - это простое манипулирование указателем с помощью смещения, известного во время компиляции, которое зависит от макета памяти B
.
Это то, что static_cast делает: статическое приведение называется статическим, поскольку вычисление того, что необходимо для преобразования, выполняется во время компиляции, будь то указатель арифметики или преобразования (*).
Однако, когда virtual
наследование пинает вещи, как правило, становится немного сложнее. Основная проблема заключается в том, что при наследовании virtual
все подклассы совместно используют один и тот же экземпляр подобъекта. Для этого B
будет иметь указатель на A
вместо A
, а объект базового класса A
будет создан вне B
.
Следовательно, во время компиляции невозможно вывести необходимую арифметику указателя: она зависит от типа объекта во время выполнения.
Всякий раз, когда есть зависимость типа времени выполнения, вам нужен RTTI (Информация о типе RunTime), и использование RTTI для приведений является задачей dynamic_cast .
В итоге:
- downcast во время компиляции:
static_cast
- время выполнения downcast:
dynamic_cast
Два других также являются приведениями во время компиляции, но они настолько специфичны, что легко запомнить, для чего они предназначены ... и они вонючие, так что лучше их вообще не использовать.
(*) Как отметил @curiousguy в комментариях, это относится только к снижению рейтинга. A static_cast
позволяет транслировать вне зависимости от виртуального или простого наследования, хотя в этом случае приведение также не требуется.