2009-10-22 66 views
17

我一直在尝试为正在处理的C++库制作一些自定义异常类。这些自定义异常会捕获调试所需的额外信息,例如文件,行号等,如果由于某种原因而在测试异常时没有找到正确的位置。然而,大多数人似乎建议继承STL中的std :: exception类,我同意这一点,但我想知道使用多继承来继承每个derived std::exception classes(例如std :: runtime_error )和一个自定义异常类,如下面的代码所示?C++中的自定义异常

另一件事,如何才能在异常类中复制构造函数和赋值运算符?他们应该被禁用?

class Exception{ 
    public: 
     explicit Exception(const char *origin, const char *file, 
          const int line, const char *reason="", 
          const int errno=0) throw(); 

     virtual ~Exception() throw(); 

     virtual const char* PrintException(void) throw(); 

     virtual int GetErrno(void); 

    protected: 
     std::string m_origin; 
     std::string m_file; 
     int m_line; 
     std::string m_reason; 
     int m_errno; 
}; 

class RuntimeError: public virtual std::runtime_error, public Exception{ 
    public: 
       explicit RuntimeError(const char *origin, const char *file, 
            const int line, const char *reason="", 
            const int errno=0) throw(); 
     virtual ~RuntimeError() throw(); 
}; 
+0

你会从中得到什么?为什么不使用单继承?为什么你需要自定义* Exception和RuntimeError异常? – jalf 2009-10-22 09:40:40

+0

我想使用我自定义的Exception类中的功能,并通过继承各种派生的std :: exception类来维护STL异常层次结构。通过这种方式搭配: 尝试throw RunTimeException(...); (std :: runtime_error&e){ ... } catch(std :: exception&e){...} 也会捕获我的自定义类。 虽然这可能是浪费时间。我也可以只用 尝试throw RunTimeException(...); } catch(std :: exception&e){...} 但它可能会使识别异常更困难。自定义异常类时,我不知道典型的做法是什么? – Tom 2009-10-22 10:16:05

+0

我会说只是从std :: runtime_error(或std :: exception)继承。如果你想要一个特定的治疗,你可以有多个捕获。 – 2009-10-22 18:36:39

回答

11

你应该尝试boost::exception

加速异常的目的是为了缓解 异常类 层次的设计和帮忙写 异常处理和错误报告 代码。

它支持任意 数据传输到catch网站,这是 否则棘手由于没有掷 要求(15.5.1)异常 类型。当异常对象 向上传播调用堆栈时,可以将数据添加到任何异常对象,直接在 的throw-expression(15.1)或 以后的时间。

他们已经传递到 后扔将数据添加到异常 物体的能力是非常重要的,因为经常的来处理 异常所需要的一些信息 是在检测到故障的情况下 不可用。

加速异常也支持异常 对象 N2179式的复制,实现非侵入 并通过 的boost :: throw_exception功能自动。

+0

我从来没有使用过提升。我会研究它。感谢这篇文章。 – Tom 2009-10-22 09:57:39

+1

非常棒的图书馆。现在我希望我以前读过它! – 2009-10-22 19:01:28

17

我在想,也许这将是更好地使用多重继承,从每一个派生的std ::的异常类继承

请注意,这是一个问题,因为这样的事实:标准库中的例外从彼此非虚拟地派生。如果您引入了多重继承,您会得到没有虚拟继承的可怕钻石异常层次结构,并且由于派生异常类携带两个子对象std::exception,因此std::exception为“模糊基类”,因此将无法通过std::exception&捕获派生异常。

具体的例子:

class my_exception : virtual public std::exception { 
    // ... 
}; 

class my_runtime_error : virtual public my_exception 
         , virtual public std::runtime_error { 
    // ... 
}; 

现在my_runtime_errorstd::exception导出(间接地)的两倍,通过my_exception一旦通过std::run_time_error和一次。因为前者不从std::exception几乎获得,这

try { 
    throw my_runtime_error(/*...*/); 
} catch(const std::exception& x) { 
    // ... 
} 

将无法​​正常工作。

编辑:

我想我见过的Stroustrup的书之一,涉及MI的异常类层次结构的第一个例子,所以我的结论是,在一般情况下,这是一个好主意。标准库的例外不会从对方中导出,我认为是失败。

当我最后设计了一个异常层次结构时,我非常广泛地使用了MI,但并没有从std lib的异常类中派生出来。在这个层次结构中,有您定义的抽象异常类,以便您的用户可以捕获它们,以及相应的实现类,这些实例类是从这些抽象类和实现基类派生的,您将实际抛出这些类。为了使这更容易,我定义了一些模板,会做所有的辛勤工作:

// something.h 
class some_class { 
private: 
    DEFINE_TAG(my_error1); // these basically define empty structs that are needed to 
    DEFINE_TAG(my_error2); // distinguish otherwise identical instances of the exception 
    DEFINE_TAG(my_error3); // templates from each other (see below) 
public: 
    typedef exc_interface<my_error1> exc_my_error1; 
    typedef exc_interface<my_error2> exc_my_error2; 
    typedef exc_interface<my_error3,my_error2> // derives from the latter 
            exc_my_error3; 

    some_class(int i); 
    // ... 
}; 

//something.cpp 
namespace { 
    typedef exc_impl<exc_my_error1> exc_impl_my_error1; 
    typedef exc_impl<exc_my_error2> exc_impl_my_error2; 
    typedef exc_impl<exc_my_error3> exc_impl_my_error3; 
    typedef exc_impl<exc_my_error1,exc_my_error2> // implements both 
            exc_impl_my_error12; 
} 
some_class::some_class(int i) 
{ 
    if(i < 0) 
    throw exc_impl_my_error3(EXC_INFO // passes '__FILE__', '__LINE__' etc. 
          , /* ... */ // more info on error 
          ); 
} 

回首现在这个样子,我想我可以作出exc_impl类模板从std::exception获得(或任何其他类std lib异常层次结构,作为可选的模板参数传递),因为它永远不会从任何其他exc_impl实例派生。但当时这不是必需的,所以它从来没有发生过。

+0

+1:很有说服力 – fmuecke 2009-10-22 09:09:10

+0

感谢帖子sbi。使用多重继承来制作异常类是一个好习惯吗?或者更好的只是从std :: exception类继承? – Tom 2009-10-22 10:02:57

+0

@Tom:我加入了我的想法作为编辑。 – sbi 2009-10-22 11:03:03