2010-03-25 7 views
27

Je suis un étudiant dans ma première classe de programmation C++, et je travaille sur un projet où nous devons créer plusieurs classes d'exceptions personnalisées, puis dans un de nos gestionnaires d'événements, utiliser un bloc try/catch pour les gérer de manière appropriée.Attraper plusieurs exceptions personnalisées? - C++

Ma question est: Comment puis-je attraper mon plusieurs exceptions personnalisées dans mon bloc try/catch? GetMessage() est une méthode personnalisée dans mes classes d'exception qui renvoie l'explication de l'exception std::string. Ci-dessous j'ai inclus tout le code pertinent de mon projet.

Merci pour votre aide!

bloc try/catch


// 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éthode


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

Juste une de mes classes d'exception personnalisées, les autres ont la même structure que celle-ci


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

Ne pas jeter les pointeurs, omettez le nouveau. – GManNickG

Répondre

38

Si vous avez plusieurs types d'exceptions, et en supposant qu'il ya une hiérarchie des exceptions (et tous dérivés publiquement de certains sous-classe de std::exception,) commencer par le plus spécifique et continuer à plus générale:

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 
} 

Sur la d'autre part, si vous êtes intéressé par tout le message d'erreur - throw même exception, dire std::runtime_error avec des messages différents, puis catch que:

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

également remembe r - lancer par valeur, attraper par référence [const].

1

Derive toutes vos exceptions d'une classe de base commune BaseException qui a une méthode virtuelle GetMessage().

Puis catch(const BaseException& e).

8

Vous devez créer une classe d'exception de base et ont toutes vos exceptions découlent:

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

Vous pouvez attraper tous dans un seul bloc catch:

catch (const BaseException& e) { } 

Si vous voulez être en mesure d'appeler GetMessage, vous devez soit:

  • placer cette logique dans BaseException, ou
  • GetMessage et de le remplacer par une fonction de membre virtuel dans BaseException dans chacune des classes d'exceptions dérivées.

Vous pouvez également envisager d'avoir vos exceptions découlent de l'une des exceptions de la bibliothèque standard, comme std::runtime_error et utiliser la fonction de membre what() idiomatiques au lieu de GetMessage().

+0

Merci pour toute l'aide! – Alex

+1

@Alex: Je ne suis pas sûr que ce soit un si bon conseil. Dans le cas général, vous ne pouvez pas contrôler les définitions de vos exceptions (par exemple, elles proviennent d'une bibliothèque, comme Boost). – einpoklum

+0

Que faire si je lance un int? ou un flotteur? Devrais-je les emballer en classe Int ou Float et puis en dériver? – quixver

0

J'ai eu un problème similaire aujourd'hui, mais il s'est avéré que je n'avais pas besoin de ma solution pour résoudre mon problème. Honnêtement, je ne pouvais pas penser à de vrais cas d'utilisation (enregistrement?), Et je n'ai pas trouvé beaucoup d'utilisation pour cela dans mon code.

Quoi qu'il en soit, il s'agit d'une approche avec des listes de types (nécessite C++ 11). Je pense que l'avantage de cette approche est qu'il n'est pas nécessaire d'avoir une classe de base commune pour les exceptions personnalisées (à l'exception de std :: exception, peut-être?). En d'autres termes, il n'est pas intrusif pour votre hiérarchie d'exceptions.

Il peut y avoir quelques erreurs subtiles dont je ne suis pas conscient.

#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

Le code ne fonctionne pas. Je n'ai pas fait attention aux tests. C'est juste un vœu pieux. Les conversions implicites ne sont pas considérées dans '' catch''. –

0

Lorsque les modèles ne le peuvent pas, les macros enregistrent le jour. La solution provient de Boost. Il se résume à 7 lignes de code.

/// @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

Ce serait bien si vous ajoutez une petite explication. –

Questions connexes