Pregunta
class CBase { };
class CDerived: public CBase { };
CBase b;
CBase* pb;
CDerived d;
CDerived* pd;
pb = dynamic_cast<CBase*>(&d); // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b); // wrong: base-to-derived
Sé que el elenco "Base to Derived" está mal. Pero, ¿cuál es la razón interior? ¿Cuál es la razón lógica en el interior? Es difícil recordar esto sin más explicación, supongo. ¡gracias!
Solución
Para la conversión derivada a base, no necesita (y generalmente no desear) para especificar un elenco explícitamente en absoluto:
CDerived d;
CBase *pb = &d; // perfectly fine
La base para el reparto derivado no está realmente mal, aunque generalmente preferiría evitarla. La razón detrás de eso es bastante simple: un puntero a la base podría estar apuntando a un objeto base real o algo derivado de él. Si vas a cásate así, generalmente debes verificar si la conversión tuvo éxito. En el caso específico que ha dado, no tendrá éxito, por lo que lo que se asigna (el resultado del dynamic_cast
) simplemente será un puntero nulo.
La mayoría de las veces, preferiría especificar una interfaz completa a los objetos de la clase en la clase base, por lo que rara vez tiene mucha necesidad de descendencia.
Otros consejos
Primero, CBase
Debe ser polimórfico para que lo use dynamic_cast
Aquí (es decir, debe tener al menos uno virtual
función miembro). De lo contrario, no puedes usar dynamic_cast
.
Dicho esto, el elenco de &b
a CDerived*
es no equivocado: pd
será un puntero nulo.
dynamic_cast
tiene la propiedad útil de que cuando el elenco falla (es decir, si el objeto señalado por el puntero no es del tipo de destino), produce un puntero nulo. Esto le permite probar el tipo real de un objeto. Por ejemplo:
CBase b;
CDerived d;
CBase* pb = &b;
CBase* pd = &d;
CDerived* xb = dynamic_cast<CDerived*>(pb); // xb is null!
CDerived* xd = dynamic_cast<CDerived*>(pd); // xd points to d!
Su código habría sido incorrecto si hubiera usado static_cast
, ya que se lanza sin realizar ninguna verificación de tipo de ejecución, lo que significa que no hay forma de probar si el elenco tuvo éxito. Si alguna vez necesita arrojar una jerarquía de clase y no sabe con certeza si el objeto es del tipo derivado al que está tratando de lanzar, debe usar dynamic_cast
.
Una clase derivada puede tener más "comportamientos" que la clase base. Más funciones de miembros, más datos de miembros, etc. Si lanza una clase base a una clase derivada, y luego intenta tratarlo como una clase derivada, intentará hacer que haga las cosas que no puede hacer. Porque estás tratando de hacer una instancia del base clase Haz cosas solo el derivado La clase sabe cómo hacer.
pd
es un puntero de tipo CDerived*
. Asi que, pd
El objeto de señalización debe tener dos subobjetos involucrados (es decir, base y derivado). Pero con esta declaración -
pd = dynamic_cast<CDerived*>(&b);
Aquí ,pd
apunta solo a un subobjecto base. No hay una forma parcial de señalar a los subobjetos. Entonces, está mal.