4

私のプロジェクトでは、基本的な例外があります。エラーダイアログ表示やログ表示などのハンドリングに。その例外のすべての派生クラスを処理する方法を探していますが、これでうまくいくと思いました:

try
{
  main_loop();
}
catch (const MyExceptionBase* e)
{
  handle_error(e);
}

スローされたすべての子インスタンスは、その親へのポインターで表すことができます。しかし、例外がスローされると、未処理の例外になります。

どうしてこれなの?c++ は参照としてのみ例外をスローしますか? それによって私の catch ブロックを役に立たなくしますか? しかし、そもそもなぜこれがコンパイルされるのでしょうか?

私が考えることができる唯一の他の方法はこれです:

try
{
  main_loop();
}
catch (const ExceptionA& e)
{
  handle_error(e);
}
catch (const ExceptionB& e)
{
  handle_error(e);
}
catch (const ExceptionC& e)
{
  handle_error(e);
}

ちょっと醜いようです。これを行う正しい方法は何ですか?基本例外クラスがありませんか? それとも、私が望む方法で解決できますか?

Ps:handle_error()基本クラス関数を使用してdisplay_message_box()、プログラムを完全にシャットダウンするだけです。

4

6 に答える 6

16

基本クラスを使用し、参照を使用するという 2 つのアプローチを組み合わせるだけです。

try
{
  main_loop();
}
catch (const MyExceptionBase& e)
{
  handle_error(e);
}

ところで、C++ は、ポインターをスローすると、ポインターをキャッチできます。しかし、それはお勧めできません。

于 2009-02-12T12:47:24.237 に答える
15

あなたの最善の策は、基本参照をキャッチすることです。ただし、ポインタではなく、参照によって行ってください。例

try
{
  main_loop();
}
catch (const MyExceptionBase& e)
{
  handle_error(e);
}

ポインターによって例外をキャッチする場合の問題は、ポインターによって例外をスローする必要があることです。これは、new で作成されることを意味します。

throw new ExceptionA();

ある時点で削除する必要があるか、メモリリークがあるため、これはかなり大きな問題を残します。この例外を削除する責任は誰にありますか? これを正しく行うのは一般的に難しいため、ほとんどの人は参照によってキャッチします。

一般に、C++ では ...

参照によるキャッチ、値によるスロー

于 2009-02-12T13:58:55.700 に答える
3

ポインターをスローする場合にのみ使用できcatch( const sometype* ptr )ます。これは、99% の状況ではお勧めできません。

機能する理由catch( const sometype& ptr )は、r 値が暗黙的に定数参照に変換できるためです。

于 2009-02-12T17:49:45.787 に答える
2

元の例が機能しないことに驚いています。以下は機能します(少なくともg ++では):

class Base { public: virtual ~Base () {} };
class Derived : public Base {};

int main ()
{
  try
  {
    throw new Derived ();
  }
  catch (Base const * b)
  {
    delete b;
  }
}

また、これが 15.3/3 の下の箇条書きに従って機能することを意図していると確信しています。

ハンドラーの型は cv1 T* cv2 であり、E はポインター型であり、次のいずれかまたは両方によってハンドラーの型に変換できます。

パブリック継承を介して基本例外タイプから継承していますか? 基本クラスはアクセス可能な基本である必要があり、これにより例外がキャッチされなくなります。

ここでの他のすべての回答によると、参照によるスロー/キャッチには、メモリの所有権などについて心配する必要がないという利点があります。ただし、上記の例が機能しない場合は、参照の理由がわかりません例が機能します。

于 2009-02-12T14:02:24.647 に答える
1

これはうまくいくはずです:

try {
  main_loop();
} catch (const MyExceptionBase &e) {
  handle_error(e);
}

私は ExceptionA/B/C がすべて MyExceptionBase から継承されていると仮定しています...それはうまくいくはずです。

PS: MyExceptionBase を std::exception から継承することも検討してください。

于 2009-02-12T12:47:02.020 に答える
0

他の人が述べたように、基本クラスの例外への参照をキャッチする必要があります。

そもそもなぜコンパイルするのかというと、Javaと違って投げたりキャッチしたりできる型に制限がない。したがって、スローされない場合でも、任意のタイプの catch ブロックを配置でき、コンパイラは喜んでそれをコンパイルします。ポインタで投げることができるので、ポインタでキャッチすることもできます。

于 2009-02-12T16:07:15.520 に答える