12
try
{
    throw Derived();
}
catch (Base&)
{
    std::cout << "subtyping\n";
}

try
{
    throw "lol";
}
catch (std::string)
{
    std::cout << "coercion\n";
}

出力:

subtyping
terminate called after throwing an instance of 'char const*'

サブタイピングでは例外処理がうまくいくのに、強制ではうまくいかないのはなぜですか?

4

2 に答える 2

18

スローされた例外をキャッチすることは、関数に引数を渡すこととはまったく異なります。類似点もありますが、微妙な違いもあります。

主な違いは次の 3 つです。

  • 例外は常に少なくとも 1 回はコピーされます (まったく回避することはできません)。
  • catch句は、宣言された順序で検査されます (ベスト フィットではありません)。
  • 型変換の対象となる形式が少なくなります
    • 継承ベースのカバー、
    • 型付きポインターから型なしポインターへの変換 (const void*任意のポインターをキャッチします)

他の種類の変換は許可されていません (たとえばint、 to double、または暗黙的なconst char*to string- あなたの例)。

コメントの質問について 階層が存在するとします。

class Base {}; 
class Derived: public Base {};
class Base2 {};
class Leaf: public Derived, public Base2 {};

句の順序に応じてcatch、適切なブロックが実行されます。

try {
    cout << "Trying ..." << endl;
    throw Leaf();

} catch (Base& b) {
    cout << "In Base&";

} catch (Base2& m) {
    cout << "In Base2&"; //unreachable due to Base&

} catch (Derived& d) {
    cout << "In Derived&";  // unreachable due to Base& and Base2&
}

順序を切り替えBaseBase2キャッチすると、異なる動作に気付くでしょう。Leafからプライベートに継承された場合Base2catch Base2&どこに配置されても到達できません ( をスローすると仮定しますLeaf)

一般的には単純です。順序が重要です。

于 2013-02-26T20:41:58.187 に答える
8

C++11標準のパラグラフ15.3/3は、ハンドラーが特定の例外オブジェクトに一致するための正確な条件を定義しており、これらはユーザー定義の変換を許可していません。

Eハンドラーは、次の場合にタイプの例外オブジェクトに一致します。

—ハンドラーはタイプcv Tまたはcv T&andETあり、同じタイプ(最上位の修飾子を無視cv)、または

—ハンドラーはタイプcv Torcv T&であり、またはTの明確なパブリックベースクラスです。E

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

  • プライベートクラス、保護されたクラス、またはあいまいなクラスへのポインタへの変換を含まない標準のポインタ変換(4.10)

  • 資格変換

—ハンドラーは、メンバー・タイプへのポインターまたはポインターであり、Eですstd::nullptr_t

[...]

于 2013-02-26T20:21:21.350 に答える