組み込み環境で作業している場合、おそらく非常に最小限のソリューションを好み、コンパイラーに関する非標準または非移植性の事実を利用できます。
クラスがC++でポリモーフィック(独自の仮想関数を少なくとも1つ持つ)である場合、そのクラスのどこかにvtableへのポインターが埋め込まれている可能性があります。vtableポインタがメモリ内のオブジェクトのレイアウトの先頭に表示されている可能性があります。
これは多くのコンパイラに当てはまります。C++ABIを使用するコンパイラです。ここで関連するSOの質問です。
その場合、次のようにvtableにアクセスできる可能性があります。
void *get_vtable(void *obj)
{
return *(reinterpret_cast<void **>(obj));
}
次に、オブジェクトへの2つのポインターのvtableを比較して、それらが同じタイプのオブジェクトを指しているかどうかを確認できます。
したがって、「タイプスイッチ」(基本的にキャッチとは)は次のようになります。
P p;
Q q;
if (get_vtable(caught) == get_vtable(&p))
{
// it's a P...
}
else if (get_vtable(caught) == get_vtable(&q))
{
// it's a Q...
}
そのパターンをCATCHマクロで非表示にすることができます。
重要なポイント-ベースからクラスを派生させたが、派生クラスが仮想関数をオーバーライドしたり、新しい仮想関数を追加したりしない場合、コンパイラーは、派生クラスに対してベースクラスのvtableを再利用できると考えられます。つまり、2つの例外タイプを区別するには、それぞれが仮想関数をオーバーライドして、独自のvtableを確実に持つ必要があります。
これは、例外処理に含まれるもののほんの一部にすぎないことに注意してください。スタックをほどくという小さな問題もあります!ハンドラーにジャンプするときは、スタック上のすべてのオブジェクトのデストラクタを呼び出す必要があります。setjmp/longjmpを実行するだけの問題ではありません。