usar try directives como clase catch c++ try-catch custom-exceptions

try - ¿Capturas múltiples excepciones personalizadas?-C++



return exception c++ (6)

Cuando las plantillas no pueden, las macros salvan el día. La solución está tomada de Boost . Se hierve a 7 líneas de código.

/// @file multicatch.hpp #include <boost/preprocessor/variadic/to_list.hpp> #include <boost/preprocessor/list/for_each.hpp> /// Callers must define CATCH_BODY(err) to handle the error, /// they can redefine the CATCH itself, but it is not as convenient. #define CATCH(R, _, T) / catch (T & err) { / CATCH_BODY(err) / } /// Generates catches for multiple exception types /// with the same error handling body. #define MULTICATCH(...) / BOOST_PP_LIST_FOR_EACH(CATCH, _, BOOST_PP_VARIADIC_TO_LIST(__VA_ARGS__)) // end of file multicatch.hpp /// @file app.cc #include "multicatch.hpp" // Contrived example. /// Supply the error handling logic. #define CATCH_BODY(err) / log() << "External failure: " << err.what(); / throw; void foo() { try { bar(); // May throw three or more sibling or unrelated exceptions. } MULTICATCH(IOError, OutOfMemory) } #undef CATCH_BODY

Soy un estudiante en mi primera clase de programación en C ++, y estoy trabajando en un proyecto en el que tenemos que crear múltiples clases de excepción personalizadas, y luego en uno de nuestros controladores de eventos, usar un bloque try/catch para manejarlos de manera apropiada.

Mi pregunta es: ¿Cómo capturo mis múltiples excepciones personalizadas en mi bloque try/catch ? GetMessage() es un método personalizado en mis clases de excepción que devuelve la explicación de la excepción como std::string . A continuación he incluido todo el código relevante de mi proyecto.

¡Gracias por tu ayuda!

try / catch block

// This is in one of my event handlers, newEnd is a wxTextCtrl try { first.ValidateData(); newEndT = first.ComputeEndTime(); *newEnd << newEndT; } catch (// don''t know what do to here) { wxMessageBox(_(e.GetMessage()), _("Something Went Wrong!"), wxOK | wxICON_INFORMATION, this);; }

Método ValidateData ()

void Time::ValidateData() { int startHours, startMins, endHours, endMins; startHours = startTime / MINUTES_TO_HOURS; startMins = startTime % MINUTES_TO_HOURS; endHours = endTime / MINUTES_TO_HOURS; endMins = endTime % MINUTES_TO_HOURS; if (!(startHours <= HOURS_MAX && startHours >= HOURS_MIN)) throw new HourOutOfRangeException("Beginning Time Hour Out of Range!"); if (!(endHours <= HOURS_MAX && endHours >= HOURS_MIN)) throw new HourOutOfRangeException("Ending Time Hour Out of Range!"); if (!(startMins <= MINUTE_MAX && startMins >= MINUTE_MIN)) throw new MinuteOutOfRangeException("Starting Time Minute Out of Range!"); if (!(endMins <= MINUTE_MAX && endMins >= MINUTE_MIN)) throw new MinuteOutOfRangeException("Ending Time Minute Out of Range!"); if(!(timeDifference <= P_MAX && timeDifference >= P_MIN)) throw new PercentageOutOfRangeException("Percentage Change Out of Range!"); if (!(startTime < endTime)) throw new StartEndException("Start Time Cannot Be Less Than End Time!"); }

Solo una de mis clases de excepciones personalizadas, las demás tienen la misma estructura que esta

class HourOutOfRangeException { public: // param constructor // initializes message to passed paramater // preconditions - param will be a string // postconditions - message will be initialized // params a string // no return type HourOutOfRangeException(string pMessage) : message(pMessage) {} // GetMessage is getter for var message // params none // preconditions - none // postconditions - none // returns string string GetMessage() { return message; } // destructor ~HourOutOfRangeException() {} private: string message; };


Debe crear una clase de excepción base y derivar todas sus excepciones específicas:

class BaseException { }; class HourOutOfRangeException : public BaseException { }; class MinuteOutOfRangeException : public BaseException { };

Luego puede atraparlos a todos en un solo bloque catch:

catch (const BaseException& e) { }

Si desea poder llamar a GetMessage , necesitará hacer lo siguiente:

  • colocar esa lógica en BaseException , o
  • hacer de GetMessage una función de miembro virtual en BaseException y anularlo en cada una de las clases de excepciones derivadas.

También podría considerar hacer que sus excepciones se deriven de una de las excepciones de la biblioteca estándar, como std::runtime_error y usar la función de miembro idiomatic what() lugar de GetMessage() .


Derive todas sus excepciones de una BaseException clase base común que tiene un método virtual GetMessage() .

Luego catch(const BaseException& e) .


Si tiene múltiples tipos de excepciones y asume que hay una jerarquía de excepciones (y todas derivadas públicamente de alguna subclase de std::exception ), comience desde la más específica y continúe con las más generales:

try { // throws something } catch ( const MostSpecificException& e ) { // handle custom exception } catch ( const LessSpecificException& e ) { // handle custom exception } catch ( const std::exception& e ) { // standard exceptions } catch ( ... ) { // everything else }

Por otro lado, si está interesado solo en el mensaje de error, throw misma excepción, diga std::runtime_error con diferentes mensajes, y luego catch eso:

try { // code throws some subclass of std::exception } catch ( const std::exception& e ) { std::cerr << "ERROR: " << e.what() << std::endl; }

Recuerde también: arrojar por valor, capturar por [const] referencia.


Tuve un problema similar hoy, pero resultó que no necesitaba mi solución para resolver mi problema. Honestamente, no podía pensar en casos de uso real (¿registro?), Y no encontré mucho uso en mi código.

De todos modos, este es un enfoque con listas de tipos (requiere C ++ 11). Creo que la ventaja de este enfoque es que no es necesario tener una clase base común para las excepciones personalizadas (excepto para std :: exception, maybe?). En otras palabras, no es intrusivo para su jerarquía de excepciones.

Puede haber algunos errores sutiles que no conozco.

#include <type_traits> #include <exception> /// Helper class to handle multiple specific exception types /// in cases when inheritance based approach would catch exceptions /// that are not meant to be caught. /// /// If the body of exception handling code is the same /// for several exceptions, /// these exceptions can be joined into one catch. /// /// Only message data of the caught exception is provided. /// /// @tparam T Exception types. /// @tparam Ts At least one more exception type is required. template <class T, class... Ts> class MultiCatch; /// Terminal case that holds the message. /// ``void`` needs to be given as terminal explicitly. template <> class MultiCatch<void> { protected: explicit MultiCatch(const char* err_msg) : msg(err_msg) {} const char* msg; }; template <class T, class... Ts> class MultiCatch : public MultiCatch<Ts...> { static_assert(std::is_base_of<std::exception, T>::value, "Not an exception"); public: using MultiCatch<Ts...>::MultiCatch; /// Implicit conversion from the guest exception. MultiCatch(const T& error) : MultiCatch<Ts...>(error.what()) {} // NOLINT /// @returns The message of the original exception. const char* what() const noexcept { return MultiCatch<void>::msg; } }; /// To avoid explicit ``void`` in the type list. template <class... Ts> using OneOf = MultiCatch<Ts..., void>; /// Contrived example. void foo() { try { bar(); // May throw three or more sibling or unrelated exceptions. } catch (const OneOf<IOError, OutOfMemory>& err) { log() << "External failure: " << err.what(); throw; // Throw the original exception. } }


#include <iostream> void test(int x)` { try{ if(x==1) throw (1); else if(x==2) throw (2.0); } catch(int a) { cout<<"It''s Integer"; } catch(double b) { cout<<"it''s Double"; } } int main(){ cout<<" x=1"; test(1); cout<<"X=2"; test(2.0); return 0; }`