c++ - Abatido en una jerarquía de diamantes
casting virtual-inheritance (2)
¿Por qué static_cast
no puede descender desde una base virtual?
struct A {};
struct B : public virtual A {};
struct C : public virtual A {};
struct D : public B, public C {};
int main()
{
D d;
A& a = d;
D* p = static_cast<D*>(&a); //error
}
g ++ 4.5 dice:
error: cannot convert from base ‘A’ to derived type ‘D’ via virtual base ‘A’
La solución es usar dynamic_cast
? pero por qué. ¿Qué es lo racional?
editar
Muy buenas respuestas a continuación. Sin embargo, no hay respuestas que detallan exactamente cómo los subobjetos y vtables terminan siendo ordenados. El siguiente artículo da algunos buenos ejemplos para gcc:
http://www.phpcompiler.org/articles/virtualinheritance.html#Downcasting
Debido a que si el objeto era en realidad de tipo E
(derivado de D), la ubicación de A
subobjeto A
relación con el subobjeto D
podría ser diferente que si el objeto fuera realmente D
En realidad, ya sucede si considera la conversión de A a C. Cuando asigna C, tiene que contener una instancia de A y vive en algún desplazamiento específico. Pero cuando asigna D, el subobjeto C se refiere a la instancia de A que vino con B, por lo que su compensación es diferente.
La respuesta obvia es: porque la norma lo dice. La motivación detrás de esto en la norma es que static_cast
debe ser casi trivial, como máximo, una simple suma o resta de una constante al puntero. Donde está el downcast a una base virtual requeriría un código más complicado: quizás incluso con una entrada adicional en el vtable en algún lugar. (Requiere algo más que constantes, ya que la posición de D
respecto a A
puede cambiar si hay una derivación adicional). La conversión es obviamente factible, ya que cuando se llama una función virtual en un A*
, la función se implementa en D
, el compilador debe hacerlo, pero la sobrecarga adicional se consideró inadecuada para static_cast
. (Presumiblemente, la única razón para usar static_cast
en estos casos es la optimización, ya que dynamic_cast
suele ser la solución preferida. Por lo tanto, cuando static_cast
probablemente sea tan costoso como dynamic_cast
todos modos, ¿por qué?)