ejemplo dynamic_cast cast c++ dynamic-cast

ejemplo - c++ dynamic_cast error handling



dynamic cast (5)

¿Hay alguna buena práctica relacionada con el manejo de errores de dynamic_cast (excepto que no la use cuando no es necesario)? Me pregunto cómo debo ir sobre NULL y bad_cast que puede arrojar. ¿Debo verificar ambos? Y si capturo bad_cast o detecté NULL probablemente no pueda recuperarme de todos modos ... Por ahora, estoy usando assert para verificar si dynamic_cast no devolvió valor NULL. ¿Aceptarías esta solución en una revisión del código?


Si y no.

boost::polymorphic_downcast<> es seguramente una buena opción para manejar los errores de dynamic_cast<> durante la fase de depuración. Sin embargo, vale la pena mencionar que polymorphic_downcast<> debe usarse solo cuando sea ​​posible predecir el tipo polimórfico pasado en tiempo de compilación , de lo contrario, se dynamic_cast<> en lugar de este.

Sin embargo, una secuencia de:

if (T1* t1 = dynamic_cast<T1*>(o)) { } if (T2* t2 = dynamic_cast<T2*>(o)) { } if (T3* t3 = dynamic_cast<T3*>(o)) { }

denota un diseño muy malo que debe resolverse mediante polimorfismo y funciones virtuales .


Depende... ;-)

Si realmente esperaba que dynamic_cast me diera algo utilizable, por ejemplo, si yo y nadie más agregara un tipo polimórfico a un contenedor de punteros a una clase base, entonces iría con el molde de referencia y dejaría que std::bad_cast kill mi aplicación - no habría mucho más que hacer, de verdad.

Sin embargo, si estoy consultando un tipo polimórfico para alguna capacidad expuesta por una interfaz que no necesariamente tiene que implementar, entonces iría con el molde del puntero y entonces un NULO no sería un error (a menos que, de Por supuesto, esperaba que la capacidad realmente estuviera allí, pero en primer lugar, me había optado por el elenco de referencia ...)


Estoy de acuerdo con la respuesta ''depende'' y también agrego "degradación elegante": el hecho de que un lanzamiento falle en alguna parte no es razón suficiente para dejar que la aplicación falle (y el usuario pierda su trabajo, etc.). Yo recomendaría una combinación de afirmaciones y programación defensiva:

ptr = dynamic_cast<MyClass>(obj); ASSERT(ptr); if(ptr) { // do stuff }


bad_cast solo se lanza cuando se lanzan referencias

dynamic_cast< Derived & >(baseclass)

Se devuelve NULL cuando se lanzan punteros

dynamic_cast< Derived * >(&baseclass)

Entonces nunca hay necesidad de verificar ambos.

Assert puede ser aceptable, pero eso depende en gran medida del contexto, y luego, eso es cierto para casi cualquier afirmación ...


Si el dynamic_cast tuviera éxito, sería una buena práctica usar boost::polymorphic_downcast lugar, que es algo como esto:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o)); return static_cast<T*>(o);

De esta forma, detectará errores en la compilación de depuración al mismo tiempo que evitará la sobrecarga de tiempo de ejecución en una compilación de lanzamiento.

Si sospecha que el lanzamiento puede fallar y desea detectarlo, use dynamic_cast y cast para un tipo de referencia. Este elenco emitirá bad_cast en caso de error y eliminará tu programa. (Esto es bueno si, como dices, no vas a recuperarte de todos modos)

T& t = dynamic_cast<T&>(o); t.func(); //< Use t here, no extra check required

Utilice dynamic_cast a un tipo de puntero solo si el 0-puntero tiene sentido en el contexto. Es posible que desee usarlo en un if como este:

if (T* t = dynamic_cast<T*>(o)) { t->func(); //< Use t here, it is valid } // consider having an else-clause

Con esta última opción, debe asegurarse de que la ruta de ejecución tenga sentido si dynamic_cast devuelve 0.

Para responder a su pregunta directamente: preferiría una de las dos primeras alternativas que he dado para tener una assert explícita en el código :)