我希望在C++中实现一个异常类,模仿.NET框架中的异常类(Java也有类似的实现),以实现以下目的:
异常链:我想要实现“异常转换”的概念,当在更高层次捕获异常并包装和“翻译”较低级别的异常时,还要以某种方式保留这些较低级别的异常(在这种情况下,在
InnerException
成员中)。为此,应该有一些机制来存储每个在上层抛出的异常的内部异常。在下面的实现中,InnerException
成员提供了这个功能。异常继承:应该可以从
Exception
派生IoException
和SerialPortException
之类的异常。虽然这似乎很简单,但应该能够动态地识别捕获的异常类型(例如,为记录日志或显示给用户),最好不需要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
是微软特有的字符串类(只针对不熟悉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++中可能的最佳实现方式?或者我完全错了吗?
P.S.:我知道在C++11中存在一些机制(也在Boost中)用于此目的(异常链接)使用一些新的异常类,但我主要感兴趣的是自定义,“旧C++兼容”的方法。同时,如果有人能提供任何在C++11中完成相同工作的代码,那将是很好的。