2016-03-23 8 views
2

私はこのことについていくつかの考えを持っているが、それが正しいかどうかわからないここでスローされた例外タイプはBですが、catch(A a)はB.派生クラスの例外が基本クラスのcatch句によってキャッチされる理由を示します。

をキャッチXcodeの

#include <iostream> 


/*Exceptions*/ 
struct A { 
    A(int value) : m_value(value) {} 
    int m_value; 
}; 

struct B : A { 
    B(int value) : A(value) {} 
}; 
//+++++++++++++++++++++++++++++++ 

/*Exceptions End*/ 

int main(int argc, const char * argv[]) { 

    try { 
     try { 
      throw B(5); 
     } 

     catch (A a) { 
      a.m_value *= 2; 
     } 
     catch (B b) { 
      b.m_value -= 2; 
      throw b; 
     } 

    } 
    catch (A a) { 
     std::cout << a.m_value; 
    } 
    return 0; 
} 

に次のコードを試してみました。私はstruct Aのためにコピーコンストラクタを追加し、Aのコピーコンストラクタは、Bタイプのオブジェクトを一致させることができますconst A&を受け付けてからだと思うし、暗黙的にこのことを確認するためにBからAへのデータ型を変換コンストラクタをコピーします。

A(const A& other) : m_value(other.m_value) { 
     std::cout << "hello\n"; 
} 

このDO出力はハローcatch(A a)を実行しながら、しかし、私はこのような明示的なコピーコンストラクタを定義する場合:

explicit A(const A& other) : m_value(other.m_value) { 
     std::cout << "hello\n"; 
} 

は、コンパイラは、「『A』の初期化に該当するコンストラクタ」を叫んだん。

なぜわからないのですか?なぜちょうどcatch(B b)にジャンプしませんでしたか?

答えて

2

この正確な問題は[except.handle]/4で覆われている:

tryブロックのハンドラは、外観の順序で試行されています。これにより、対応する ベースクラスのハンドラの後に、派生クラス用のハンドラを配置することによって、など が実行されないハンドラを記述することが可能になります。あなたが有効に警告してコンパイルした場合

、それも明確になるであろう:

main.cpp:28:9: warning: exception of type 'B' will be caught 
     catch (B b) { 
     ^
main.cpp:24:9: warning: by earlier handler for 'A' 
     catch (A a) { 
     ^

はそうです、何がBがスローされ、一度で起こってしまい、私たちはただのハンドラ1のリストによると下ります1。 Aまでキャッチできますか?はい、できます! BAに変換可能です。

Aのコピーコンストラクタを作成すると、面白いことが起こります。暗黙的にBAに変換することはできませんが、これは例外ロジックの処理とは異なります。これは単にタイプをチェックします。 [except.handle]/3によれば、ハンドラタイプCVT又はCVT&である - - [...]

場合

ハンドラEの例外オブジェクトの一致でありますTは、E、または
の曖昧さのない公開ベースクラスです。]我々の場合には

を、ABの明確な公共の基底クラスで、ハンドラはタイプAであり、そのハンドラが一致しました。完全停止。さて、実際にはを使用することはできません。ハンドラを使用すると、コードが不正です。

+0

非常に簡単!ありがとうございました! – Curtis2

0

が最初に来たので。これはC++の誤った機能です。理想的には、catchブロックのコンパイルエラーが発生しているか、少なくとも到達不能なコードの場合はコンパイルエラーが発生していました。最初にcatch (B ...)と記入してください。

+0

問題は、コピーコンストラクタを明示的に定義すると、コンパイルされません。 – Curtis2

+0

参照でcatchするべきです: 'catch(A&...)'、Bと同様です。値で例外をキャッチする理由はありません。可能であればconst参照。 – EJP

+0

私は知っていますが、これはインタビューの質問からです。そして、参照によっても、値が渡されているので、まだ解読されています。 – Curtis2

関連する問題