1

例外の階層を作成したいと思います。私はC++イディオム「PolymorphicException」を使用しました。

難しいのは、これらのクラスを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;
}

これを達成する方法について何か考えはありますか?

前もって感謝します!

4

1 に答える 1

2

例外はいつでも再スローできます。キャッチの間に発生した場合に定義されます。例えば:

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
        }
    }
};
于 2012-06-16T22:38:23.277 に答える