我想在 C++ 中实现一个模仿 .NET 框架的异常类(Java 也有类似的东西),用于以下目的:
异常链接:我想实现“异常转换”的概念,当在较高级别捕获的异常包装并“转换”较低级别的异常时,还以某种方式保留这些较低级别的异常(
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);
}
并且在最上层捕获“最外层”异常时,我希望能够通过InnerException
成员解析和格式化整个异常链,以显示如下内容:
到目前为止,我已经提出了以下实现:
小提示: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;
};
现在我们在这里有什么。复制构造函数和赋值运算符是protected
为了防止复制。每个对象都将“拥有”其内部异常对象(并在析构函数中将其删除),因此默认的浅拷贝是不可接受的。然后我们有两个非常标准的构造函数和删除InnerException
对象的虚拟析构函数。Clone()
虚方法负责对对象进行深拷贝,主要用于存储内部异常对象(见第二个构造函数)。最后,GetExceptionName()
虚拟方法为识别异常类名称提供了 RTTI 的廉价替代方法(我不认为这看起来很酷,但我想不出更好的解决方案;作为比较:在 .NET 中可以简单地使用someException.GetType().Name
)。
现在这完成了工作。但是......我不喜欢这个解决方案有一个特殊的原因:每个派生类所需的编码量。考虑我必须派生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;
}
};
我不喜欢每次都必须提供protected
复制构造函数和赋值运算符的事实,我不喜欢Clone
每次都必须克隆方法,甚至复制复制基本成员的代码(InnerException
... ),简单地说......我认为这不是优雅的解决方案。但我想不出更好的。您对如何“正确”实施这个概念有任何想法吗?或者这可能是 C++ 中这个概念的最佳实现?或者,也许我这样做完全错了?
PS:我知道 C++11(也在 Boost 中)为此目的(异常链接)存在一些机制,并带有一些新的异常类,但我主要对自定义的“旧 C++ 兼容”方式感兴趣。但是,另外,如果有人可以提供任何 C++11 中的代码来完成同样的事情,那就太好了。