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!

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top