【问题标题】:C++: How to handle exceptions deriving from std:exception differently depending on their type?C ++:如何根据其类型以不同方式处理源自 std:exception 的异常?
【发布时间】:2012-06-16 22:34:03
【问题描述】:

我想创建一个异常层次结构。我使用了 C++ 习语“多态异常”。

困难的一点是我希望这些类从 std::exception 派生 - 能够使用 try ... catch(exception &e) 在代码的任何点捕获任何异常。

但是,无论异常来自 std::exception 还是来自我的用户定义的异常,我都想以不同的方式处理异常。

这建议使用多态性,但是我不能在 std::exception 上定义虚函数。

我也尝试过使用函数模板(参见下面的代码),但它不起作用,因为调用的模板函数是在编译时确定的。

#include <iostream>
#include <string>
using namespace std;

#include <boost\type_traits\is_base_of.hpp>
#include <boost\utility\enable_if.hpp>


class BaseError :public exception {
  public:
    virtual void raise(){throw *this;}
    virtual string msg (){ return "This is the base class"; }
  };

class DerivedError: public BaseError {
  public:
    void raise(){throw *this;}
    string msg (){ return "This is the derived class"; }
  };

template <typename T>
typename boost::disable_if<boost::is_base_of<BaseError, T>>::type
handleException(T &e)
{
    cout << "Handling generic exception" << endl;
    cout << e.what() << endl;
}
template <typename T>
typename boost::enable_if<boost::is_base_of<BaseError, T>>::type
handleException(T &e)
{
    cout << "Handling specific exception" << endl;
    cout << e.msg() << endl;
}


int main () {
  BaseError b;
  handleException(b);
  // prints "Handling specific exception"
  // prints "This is the base class"
  try{
      throw exception("Exception !!!");
  }
  catch (exception &e){
      handleException(e);
      // prints "Handling generic exception"
      // prints "Exception !!!"
  }
  try{
      BaseError b;
      b.raise();
  }
  catch (exception &e){
      handleException(e);
      // prints "Handling generic exception" - I would like the specific behaviour
      // prints "Unknown exception"
  }
  try{
      DerivedError d;
      d.raise();
  }
  catch (exception &e)
  {
      handleException(e);
      // prints "Handling generic exception" - I would like the specific behaviour
      // prints "Unknown exception"
  }
  return 0;
}

知道如何实现这一点吗?

提前致谢!

【问题讨论】:

    标签: c++ exception-handling derived-class


    【解决方案1】:

    您可以在任何时候重新抛出异常,如果它发生在 catch 之间,它将被定义。例如:

    try
    {
        // something that throws an exception
    } catch(std::exception& e) {
        try
        {
            throw; // rethrows the original exception
        } catch(std::runtime_error& e) {
            // handle runtime error
        } catch(std::exception& e) {
            // handle everything else
        }
    }
    

    现在嵌套的try-catch 块可以在任何地方,它可以是一个函数甚至是一个对象析构函数。您可以组合一组处理特定异常的对象,将它们链接在一起并在链的末尾调用throw;。伪代码:

    template< typename E, typename Base = void >
    struct exception_handler : Base
    {
        void handle() const
        {
            try
            {
                Base::handle();
            } catch( E& e ) {
                // do something
            }
        }
    };
    
    template< typename E >
    struct exception_handler< E, void >
    {
        void handle() const
        {
            try
            {
                throw;
            } catch( E& e ) {
                // do something
            }
        }
    };
    

    那么上面的例子可以这样理解:

    try
    {
        // something that throws an exception
    } catch(std::exception& e) {
        exception_handler<
            std::exception
          , exception_handler<
                std::runtime_error
            >
        > handler;
        handler.handle();
    }
    

    可以使用继承和常规类手动创建相同的层次结构,您可以在其中定义每个异常级别以及如何处理它们。

    struct runtime_error_handler : base_handler
    {
        void handle() const
        {
            try
            {
                throw;
            } catch( std::runtime_error& e ) {
                // if the original exception was a runtime_error it will be caught here
                // otherwise it will be propagated up the stack to exception_handler
    
                // do something if runtime_error
            }
        }
    };
    
    struct exception_handler : runtime_error_handler
    {
        void handle() const
        {
            try
            {
                runtime_error_handler::handle();
            } catch(std::exception& e) {
                // do something else in the general case
            }
        }
    };
    

    【讨论】:

    • 您好 K-ballo,感谢您的及时答复!您的第一点解决了我的问题,不知道为什么我没有考虑过......但是我真的很喜欢嵌套模板的想法,我会尝试实现这个解决方案。最好的,
    • @user1461163:这么早结束这么好的问题真是太可惜了......无论如何,你可能想看看 Boost.Exception 的内部结构,它需要一个与此处的方法类似。
    • 我当然会。这是我在这个论坛上的第一个问题,我一定会发布更多!再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2015-09-24
    • 1970-01-01
    • 1970-01-01
    • 2013-01-28
    • 1970-01-01
    相关资源
    最近更新 更多