2010-03-25 38 views
27

Tôi là sinh viên trong lớp lập trình C++ đầu tiên và đang làm việc trên một dự án nơi chúng tôi phải tạo nhiều lớp ngoại lệ tùy chỉnh và sau đó là một trong các trình xử lý sự kiện của chúng tôi, sử dụng khối try/catch để xử lý chúng thích hợp.Bắt nhiều ngoại lệ tùy chỉnh? - C++

Câu hỏi của tôi là: Làm cách nào để bắt được nhiều ngoại lệ tùy chỉnh trong khối try/catch của tôi? GetMessage() là phương thức tùy chỉnh trong các lớp ngoại lệ của tôi trả về giải thích ngoại lệ dưới dạng std::string. Dưới đây tôi đã bao gồm tất cả các mã có liên quan từ dự án của tôi.

Cảm ơn sự giúp đỡ của bạn!

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

ValidateData() Phương pháp


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

Chỉ cần một các lớp ngoại lệ tùy chỉnh của tôi, những người khác có cấu trúc tương tự như thế này một


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

Đừng ném con trỏ, bỏ qua cái mới. – GManNickG

Trả lời

38

Nếu bạn có nhiều loại ngoại lệ, và giả sử có một hệ thống các trường hợp ngoại lệ (và tất cả bắt nguồn công khai từ một số lớp con của std::exception,) bắt đầu từ cụ thể nhất và tiếp tục tổng quát hơn:

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 
} 

Trên Mặt khác, nếu bạn quan tâm đến chỉ được thông báo lỗi - throw cùng ngoại lệ, nói std::runtime_error với những thông điệp khác nhau, và sau đó catch rằng:

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

Cũng remembe r - ném theo giá trị, bắt bằng tham chiếu [const].

1

Rút ra tất cả các trường hợp ngoại lệ của bạn từ một lớp cơ sở chung BaseException rằng có một phương thức ảo GetMessage().

Sau đó, catch(const BaseException& e).

8

Bạn nên tạo một lớp cơ sở ngoại lệ và có tất cả các trường hợp ngoại lệ cụ thể của bạn bắt nguồn từ nó:

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

Sau đó bạn có thể bắt tất cả chúng trong một khối catch duy nhất:

catch (const BaseException& e) { } 

Nếu bạn muốn có thể gọi số GetMessage, bạn cần phải:

  • đặt logic đó vào BaseException hoặc
  • làm cho GetMessage chức năng thành viên ảo trong BaseException và ghi đè nó trong mỗi lớp ngoại lệ có nguồn gốc.

Bạn cũng có thể xem xét việc có trường hợp ngoại lệ của bạn xuất phát từ một trong những trường hợp ngoại lệ thư viện tiêu chuẩn, như std::runtime_error và sử dụng chức năng what() viên thành ngữ thay vì GetMessage().

+0

Cảm ơn tất cả sự giúp đỡ! – Alex

+1

@ Alex: Tôi không chắc đây là lời khuyên tuyệt vời như vậy. Trong trường hợp chung, bạn không thể kiểm soát các định nghĩa về ngoại lệ của mình (ví dụ: chúng là từ một số thư viện, chẳng hạn như Boost). – einpoklum

+0

Nếu tôi ném int thì sao? hoặc một phao? Tôi có nên bọc chúng trong lớp Int hoặc Float và sau đó lấy được từ chúng? – quixver

0

Tôi đã có một vấn đề tương tự ngày hôm nay, nhưng hóa ra tôi không cần giải pháp của mình để giải quyết vấn đề của mình. Thành thật mà nói, tôi không thể nghĩ ra trường hợp sử dụng thực tế (đăng nhập?), Và tôi đã không tìm thấy nhiều sử dụng cho nó trong mã của tôi.

Dù sao, đây là cách tiếp cận với danh sách loại (yêu cầu C++ 11). Tôi nghĩ rằng lợi thế của phương pháp này là không cần phải có một lớp cơ sở chung cho các ngoại lệ tùy chỉnh (ngoại trừ std :: exception, có thể?). Nói cách khác, nó không xâm nhập vào hệ thống phân cấp ngoại lệ của bạn.

Có thể có một số lỗi nhỏ mà tôi không biết.

#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

Mã không hoạt động. Tôi không chú ý đến thử nghiệm. Đây chỉ là một suy nghĩ mơ ước. Chuyển đổi ngầm định không được xem xét trong '' catch''. –

0

Khi mẫu không thể, macro lưu ngày. Giải pháp được lấy từ Boost. Nó chứa 7 dòng mã.

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

Sẽ tốt nếu bạn thêm một lời giải thích nhỏ. –

Các vấn đề liên quan