- Цепочка исключений: я хотел бы реализовать концепцию «трансляции исключений», когда исключения, перехваченные на более высоких уровнях, оборачивают и «транслируют» исключения более низкого уровня, а также каким-то образом сохраняя эти исключения более низкого уровня (в элементе InnerException, в этом случай). Для этого должен быть какой-то механизм для хранения внутренних исключений вместе с каждым исключением, возникающим на верхнем уровне. Член InnerException обеспечивает это в реализации ниже.
- Наследование исключений: должна быть возможность получить IoException из Exception и SerialPortException, например, из IoException. Хотя это кажется тривиальным, должна быть возможность динамически определять тип перехваченных исключений (например, для целей регистрации или для отображения пользователю), желательно без накладных расходов на RTTI и typeid.
Код: Выделить всё
try
{
try
{
try
{
throw ThirdException(L"this should be ThirdException");
}
catch(Exception &ex)
{
throw SubException(L"this should be SubException", ex);
}
}
catch(Exception &ex)
{
throw SubException(L"this should be SubException again", ex);
}
}
catch(Exception &ex)
{
throw Exception(L"and this should be Exception", ex);
}

Я придумал следующую реализацию, поэтому далеко:
Небольшое примечание: CString — это строковый класс, специфичный для Microsoft (только для людей, не знакомых с Visual C++).
Код: Выделить всё
class Exception
{
protected:
Exception(const Exception&) {};
Exception& operator= (const Exception&) {};
public:
Exception(const CString &message) : InnerException(0), Message(message) {}
Exception(const CString &message, const Exception &innerException) : InnerException(innerException.Clone()), Message(message) {}
virtual CString GetExceptionName() const { return L"Exception"; }
virtual Exception *Clone() const
{
Exception *ex = new Exception(this->Message);
ex->InnerException = this->InnerException ? this->InnerException->Clone() : 0;
return ex;
}
public:
virtual ~Exception() { if (InnerException) delete InnerException; }
CString Message;
const Exception *InnerException;
};
Теперь это делает свою работу. Но... Мне не нравится это решение по одной конкретной причине: объем кода, необходимый для каждого производного класса. Предположим, мне нужно получить класс SubException, который не предоставляет абсолютно никаких дополнений к функциональности базового класса, он просто предоставляет собственное имя («SubException», которое может быть «IoException», «ProjectException», ...), чтобы дифференцировать его для сценария использования. Мне нужно предоставить почти одинаковое количество кода для каждого такого класса исключений. Вот оно:
Код: Выделить всё
class SubException : public Exception
{
protected:
SubException(const SubException& source) : Exception(source) {};
SubException& operator= (const SubException&) {};
public:
SubException(const CString &message) : Exception(message) {};
SubException(const CString &message, const Exception &innerException) : Exception(message, innerException) {};
virtual CString GetExceptionName() const { return L"SubException"; }
virtual Exception *Clone() const
{
SubException *ex = new SubException(this->Message);
ex->InnerException = this->InnerException ? this->InnerException->Clone() : 0;
return ex;
}
};
Код: Выделить всё
InnerExceptionP.S.: Я знаю, что в C++11 (также в Boost) существуют некоторые механизмы для этой цели (цепочка исключений) с некоторыми новыми классами исключений, но меня в первую очередь интересуют специальные, "совместимые со старым C++" способы. Но кроме того, было бы хорошо, если бы кто-нибудь мог предоставить какой-нибудь код на C++11, который выполняет то же самое.
Подробнее здесь: https://stackoverflow.com/questions/133 ... n-chaining
Мобильная версия