多重継承を使用する場合に仮想継承が必要であることは理解しています。これにより、恐ろしいダイヤモンド問題が解決されます。
しかし、多重継承を使用していない場合はどうなるでしょうか? 仮想継承の必要性はまったくありますか?
例外 (派生クラスのスロー、基底クラス参照によるキャッチ) にとって重要であると聞いたことを覚えているようです。しかし、それには仮想デストラクタで十分ではないでしょうか?
これでかつて見た参考ページを探してみたのですが、なかなか見つかりません。
多重継承を使用する場合に仮想継承が必要であることは理解しています。これにより、恐ろしいダイヤモンド問題が解決されます。
しかし、多重継承を使用していない場合はどうなるでしょうか? 仮想継承の必要性はまったくありますか?
例外 (派生クラスのスロー、基底クラス参照によるキャッチ) にとって重要であると聞いたことを覚えているようです。しかし、それには仮想デストラクタで十分ではないでしょうか?
これでかつて見た参考ページを探してみたのですが、なかなか見つかりません。
おそらく、このBoost.Exception ガイドラインについて考えているでしょう。完全を期すためにここにコピーします。
例外タイプは、他の例外タイプから派生する場合、仮想継承を使用する必要があります。この洞察は、Andrew Koenig によるものです。仮想継承を使用すると、例外ハンドラーのあいまいさの問題が回避されます。
#include <iostream>
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};
int
main()
{
try { throw your_exc3(); }
catch(std::exception const& e) {}
catch(...) { std::cout << "whoops!" << std::endl; }
}
上記のプログラムは、「whoops!」を出力します。std::exception への変換があいまいであるためです。
仮想継承によって導入されるオーバーヘッドは、例外処理のコンテキストでは常に無視できます。仮想ベースは、最も派生した型 (例外の場合に throw ステートメントに渡される型) のコンストラクターによって直接初期化されることに注意してください。これにより、例外タイプをメンバーのない自明な構造体にすることができます (初期化するものは何もありません)。単純なセマンティック タグとしての例外タイプを参照してください。
はい、例外クラスに複数の継承が含まれる場合。
仮想継承の唯一のコストは vtable で、それほどコストはかかりません。仮想継承を使用すると、後で人々がさまざまなものから継承した後、二重ダイヤモンドの問題が予期せず醜い頭をもたげることがなくなります。これは、クラスが適切な基本クラスになることを意味します。
いいえ、ダイヤモンドの問題を解決する以外には必要ありません。あなたは物事を想像しているに違いありません!
多重継承を使用する場合に仮想継承が必要であることは理解しています。これにより、恐ろしいダイヤモンド問題が解決されます。
しかし、多重継承を使用していない場合はどうなるでしょうか?
質問 (ほとんどが修辞的): MI が使用されないことをどのように知ることができますか?
答え: それを知ることはできません。(あなたがそうすることが証明されるまで。)
例外 (派生クラスのスロー、基底クラス参照によるキャッチ) にとって重要であると聞いたことを思い出したようです。しかし、それには仮想デストラクタで十分ではないでしょうか?
質問 (修辞): ここで仮想デストラクタが必要なのはなぜですか?
答え: そうではありません。