C++における基底クラスと派生クラスの例外キャッチ:正しい順序の重要性
C++で基底クラスと派生クラスの両方の例外を捕捉したい場合は、派生クラスのcatchブロックを基底クラスのcatchブロックよりも必ず先に配置する必要があります。この順序を守らないと、派生クラスのcatchブロックは決して実行されず、常に基底クラス側が処理を引き受けてしまいます。
これは、C++の例外処理が上から順に型の一致判定を行う仕組みになっているためです。派生クラスのオブジェクトは基底クラスの型としても扱えるため、基底クラスのcatchブロックが先にあると、そこで例外が捕捉されてしまうのです。
アルゴリズム
Begin
クラスBを宣言する。
クラスBを継承する別のクラスDを宣言する。
クラスDのオブジェクトを生成する。
Try: 派生オブジェクト(derived)をthrowする。
Catch (D derived)
「Caught Derived Exception」を出力する。
Catch (B b)
「Caught Base Exception」を出力する。
End.例1:派生クラスのcatchを先に記述した場合
以下は、派生クラスのcatchブロックを基底クラスのcatchブロックより前に配置したシンプルな例です。出力結果を確認してみましょう。
#include<iostream>
using namespace std;
class B {};
class D: public B {}; // クラスDはクラスBを継承
int main() {
D derived;
try {
throw derived;
}
catch(D derived){
cout<<"Caught Derived Exception"; // 派生クラスのcatchブロック
}
catch(B b) {
cout<<"Caught Base Exception"; // 基底クラスのcatchブロック
}
return 0;
}出力
Caught Derived Exception
期待どおり、派生クラスのcatchブロックが実行されました。
例2:基底クラスのcatchを先に記述した場合
次に、逆に基底クラスのcatchブロックを派生クラスのcatchブロックより前に配置した例を見てみましょう。
#include<iostream>
using namespace std;
class B {};
class D: public B {}; // クラスDはクラスBを継承
int main() {
D derived;
try {
throw derived;
}
catch(B b) {
cout<<"Caught Base Exception"; // 基底クラスのcatchブロック
}
catch(D derived){
cout<<"Caught Derived Exception"; // 派生クラスのcatchブロック
}
return 0;
}出力
Caught Base Exception
まとめ
このように、throwされたのが派生クラスのオブジェクトであっても、基底クラスのcatchブロックが先に書かれていると、そちらで例外が捕捉されてしまいます。多くのコンパイラでは、到達不能な派生クラスのcatchブロックに対して警告が出ることもあります。
したがって、派生クラスのcatchブロックは必ず基底クラスのcatchブロックより前に配置することが、C++の例外処理における重要なルールです。これにより、より具体的な(派生クラスの)例外を優先的に、かつ適切に処理できるようになります。
-
C#の共変性と反変性とは?初心者向けに基本概念をわかりやすく解説
はじめに C#でクラスを効果的に扱うためには、「共変性」と「反変性」という概念を理解しておくことが非常に役立ちます。これらは一見とっつきにくい言葉ですが、仕組みをつかめば型の扱いがぐっと柔軟になり、コードの再利用性も高まります。 継承関係を持つサンプルクラス まずは、以下のように3つのクラスを定義してみましょう。「Two」は基底クラス「One」を継承した派生クラスであり、さらに「Three」は「Two」を継承しています。 class One { } class Two: One { } class Three : Two { } つまり、継承の階層は「One → Two → Thre
-
Pythonの例外基本クラス徹底解説|BaseExceptionと例外階層、独自例外の作り方
Pythonにおける例外とは Pythonには、他の高水準言語と同様に例外(Exception)の仕組みが備わっています。プログラムの実行中に問題が検出されると例外が発生(raise)し、適切に処理しなければプログラムはその時点で中断されます。代表的な例外には、ゼロ除算を表すZeroDivisionErrorや、アサーションの失敗を表すAssertionErrorなど、さまざまな種類があります。 すべての例外クラスはBaseExceptionクラスから派生しています。開発者は組み込みの例外をそのまま利用できるだけでなく、raise文を使ってコード中で意図的に例外を発生させることもできます。さら