Muốn THÊM các câu trả lời khác được mô tả ở đây một ghi chú bổ sung, trong trường hợp ngoại lệ tùy chỉnh .
Trong trường hợp bạn tạo ngoại lệ tùy chỉnh của riêng mình, xuất phát từ std::exception
, khi bạn bắt được các loại ngoại lệ "tất cả có thể", bạn phải luôn bắt đầu các catch
mệnh đề với loại ngoại lệ "có nguồn gốc nhất" có thể bị bắt. Xem ví dụ (về những gì KHÔNG nên làm):
#include <iostream>
#include <string>
using namespace std;
class MyException : public exception
{
public:
MyException(const string& msg) : m_msg(msg)
{
cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
}
~MyException()
{
cout << "MyException::~MyException" << endl;
}
virtual const char* what() const throw ()
{
cout << "MyException - what" << endl;
return m_msg.c_str();
}
const string m_msg;
};
void throwDerivedException()
{
cout << "throwDerivedException - thrown a derived exception" << endl;
string execptionMessage("MyException thrown");
throw (MyException(execptionMessage));
}
void illustrateDerivedExceptionCatch()
{
cout << "illustrateDerivedExceptionsCatch - start" << endl;
try
{
throwDerivedException();
}
catch (const exception& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
// some additional code due to the fact that std::exception was thrown...
}
catch(const MyException& e)
{
cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
// some additional code due to the fact that MyException was thrown...
}
cout << "illustrateDerivedExceptionsCatch - end" << endl;
}
int main(int argc, char** argv)
{
cout << "main - start" << endl;
illustrateDerivedExceptionCatch();
cout << "main - end" << endl;
return 0;
}
GHI CHÚ:
0) Thứ tự thích hợp phải là ngược lại, tức là - đầu tiên bạn catch (const MyException& e)
được theo sau catch (const std::exception& e)
.
1) Như bạn có thể thấy, khi bạn chạy chương trình như hiện tại, mệnh đề bắt đầu tiên sẽ được thực thi (đó có thể là điều bạn KHÔNG muốn ở vị trí đầu tiên).
2) Mặc dù loại được bắt trong mệnh đề bắt đầu tiên là loại std::exception
, phiên bản "thích hợp" what()
sẽ được gọi - vì nó bị bắt bởi tham chiếu (thay đổi ít nhất là std::exception
loại đối số bị bắt thành giá trị - và bạn sẽ trải nghiệm hiện tượng "cắt đối tượng" trong hành động).
3) Trong trường hợp "một số mã do thực tế là ngoại lệ XXX bị ném ..." thực hiện công cụ quan trọng VỚI TRÁCH NHIỆM đối với loại ngoại lệ, có mã lỗi của bạn ở đây.
4) Điều này cũng phù hợp nếu các đối tượng bị bắt là đối tượng "bình thường" như: class Base{};
và class Derived : public Base {}
...
5) g++ 7.3.0
trên Ubuntu 18.04.1 tạo cảnh báo cho biết sự cố được đề cập:
Trong hàm 'void IllustrateDerivingExceptionCatch ()': item12Linux.cpp: 48: 2: cảnh báo: ngoại lệ của loại 'MyException' sẽ bị bắt (const MyException & e) ^ ~~~ ~
item12Linux.cpp: 43: 2: cảnh báo: bởi trình xử lý trước đó cho 'std :: ngoại lệ'
bắt (const ngoại lệ & e) ^ ~~~ ~
Một lần nữa , tôi sẽ nói rằng câu trả lời này chỉ để THÊM cho các câu trả lời khác được mô tả ở đây (tôi nghĩ rằng điểm này đáng được đề cập, nhưng không thể mô tả nó trong một bình luận).