2010-03-25 15 views
27

Soy un estudiante en mi primera clase de programación en C++, y estoy trabajando en un proyecto donde tenemos que crear múltiples clases de excepciones personalizadas, y luego en uno de nuestros controladores de eventos, usar un bloque try/catch para manejarlas adecuadamente.¿Capturas múltiples excepciones personalizadas? - C++

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

Gracias por su ayuda!

try/catch bloque


// 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);; 
} 

ValidateData() Método


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!"); 
} 

Sólo una de mis clases de excepción personalizados, los otros tienen la misma estructura que éste


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; 
}; 
+2

No tire punteros, omiten la nueva. – GManNickG

Respuesta

38

Si tiene varios tipos de excepción, y suponiendo que hay una jerarquía de excepciones (y todos los derivados públicamente de alguna subclase de std::exception,) comenzar desde la más específica y continuar más general:

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 por otro lado, si usted está interesado sólo en el mensaje de error - throw misma excepción, decir std::runtime_error con diferentes mensajes, y luego catch que:

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

también remembe r - arrojar por valor, capturar por [const] referencia.

1

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

Luego catch(const BaseException& e).

8

Debe crear una clase de excepción base y tener todas sus excepciones específicas se deben a que:

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

A continuación, puede coger todos ellos en un solo bloque catch:

catch (const BaseException& e) { } 

Si Si desea poder llamar al GetMessage, necesitará:

  • colocar esa lógica en BaseException, o
  • hacen que GetMessage sea una función de miembro virtual en BaseException y lo sobrescriban en cada una de las clases de excepciones derivadas.

También puede considerar que tiene sus excepciones derivan de una de las excepciones de la biblioteca estándar, como std::runtime_error y utilizar la función what() miembro idiomática en lugar de GetMessage().

+0

¡Gracias por toda la ayuda! – Alex

+1

@Alex: No estoy seguro de que este sea un gran consejo. En el caso general, no puede controlar las definiciones de sus excepciones (por ejemplo, son de alguna biblioteca, como Boost). – einpoklum

+0

¿Qué pasa si lanzo un int? o una carroza? ¿Debo envolverlos en clase Int o Float y luego derivarlos? – quixver

0

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. 
    } 
} 
+0

El código no funciona. No presté atención a las pruebas. Esto es solo una ilusión. Las conversiones implícitas no se consideran en '' catch''. –

0

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 
-1

 

#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; }`
+1

Sería bueno si agrega una pequeña explicación. –

Cuestiones relacionadas