2010-03-25 30 views
27

İlk C++ programlama sınıfımdaki bir öğrenciyim ve birden çok özel özel durum sınıfı oluşturmamız gereken bir proje üzerinde çalışıyorum ve daha sonra olay işleyicilerimizden birinde, bunları işlemek için bir try/catch blok kullanın uygun şekilde.Birden Çok Özel Özel Durum mu Yakalayın? - C++

Soruma ilişkin soru: try/catch bloğumdaki çoklu özel istisnalarımı nasıl yakalarım? GetMessage(), istisna açıklamalarım std::string olarak döndüren özel durum sınıflarımdaki özel bir yöntemdir. Aşağıda tüm ilgili kodu projemden ekledim.

Yardımlarınız için teşekkürler!

deneme/yakalama bloğu


// 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() Metodu


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

Sadece bir Benim özel istisna sınıfları, diğerleri sanal yöntem GetMessage() sahip ortak bir temel sınıf BaseException adresinin istisnalar tüm türetin bu bir


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

, işaretçileri atmak yeni ihmal etmeyin. – GManNickG

cevap

38

Birden istisna türü vardır ve en özel başlayıp daha genel devam istisnalar hiyerarşi var varsayarak (ve tüm std::exception bazı alt sınıf, kamuya türetilmiş) ise:

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 
} 

günü sadece hata iletisinde ilgileniyorsanız Öte yandan, - throw aynı istisna, farklı mesajlarla std::runtime_error de, sonra catch o: Remembe Ayrıca

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

r - değere göre atla, [const] referansıyla yakala.

1

aynı yapıya sahiptir.

catch(const BaseException& e).

Bir baz istisna sınıfı oluşturmak ve özel istisnalar tüm olmalıdır
8

ondan türetmek:

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

Daha sonra tek catch bloğunda hepsini yakalamak:

catch (const BaseException& e) { } 

ise GetMessage'u arayabilmeniz için şunlara ihtiyacınız olacaktır:

  • bu mantığı 0'a dönüştürün., veya
  • , öğesinin bir sanal üye işlevini BaseException içinde yapın ve türetilen özel durum sınıflarının her birinde bu değeri geçersiz kılın. Ayrıca özel durumları olan düşünebilirsiniz

std::runtime_error gibi standart kütüphane istisnalardan biri, türetme ve GetMessage() yerine deyimsel what() üye işlevini kullanın.

+0

Yardım için teşekkürler! – Alex

+1

@Alex: Bunun harika bir tavsiye olduğundan emin değilim. Genel durumda, istisnalarınızın tanımlarını kontrol edemezsiniz (örneğin, Boost gibi bazı kütüphanelerden geliyorlar). – einpoklum

+0

Bir int yaparsam ne olur? ya da bir kayan nokta mı? Onları Int veya Float sınıfında tamamlayıp onlardan türetmeli miyim? – quixver

0

Bugün de benzer bir sorun yaşadım, ancak sorunumu çözmek için çözümüme ihtiyacım olmadığı ortaya çıktı. Dürüst olmak gerekirse, gerçek kullanım durumlarını düşünemedim (günlüğe kaydediliyor mu?) Ve kodumda bunun için fazla bir şey bulamadım. Her neyse, bu tip listeleri ile bir yaklaşımdır (C++ 11 gerektirir). Bu yaklaşımın avantajının, özel istisnalar için ortak bir temel sınıfa gerek duyulmaması gerektiğine inanıyorum (std :: exception hariç, belki?). Başka bir deyişle, istisna hiyerarşiniz için müdahaleci değildir.

Farkında olmadığım bazı ince hatalar olabilir.

#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

Kod çalışmıyor. Testlere dikkat etmedim. Bu sadece arzulu bir düşünce. Örtülü dönüşümler "yakalama" da dikkate alınmaz. –

0

Şablonlar yapamadığı zaman, makrolar günü kaydeder. Çözüm, Boost'dan alınmıştır. Kod 7 satırına kadar kaynar.

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

Küçük bir açıklama eklerseniz iyi olur. –