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
GetMessageuna función de miembro virtual enBaseExceptiony 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;
}`