C++のRTTI(実行時型情報)とは?dynamic_castの使い方を解説
RTTI(実行時型情報)とは
この記事では、C++におけるRTTI(Runtime Type Information:実行時型情報)について詳しく解説します。RTTIとは、プログラムの実行時にオブジェクトのデータ型に関する情報を取得・判定できる仕組みのことです。これにより、実行中のプログラム内でオブジェクトの実際の型を動的に判別することが可能になります。
ただし、この機能が有効になるのは、クラスに少なくとも1つの仮想関数(virtual関数)が定義されている場合のみです。つまり、RTTIは多態性(ポリモーフィズム)を持つクラスに対してのみ利用できます。
仮想関数がない場合の例
次のサンプルコードは、仮想関数を持たないため正しく動作しません。コンパイル時に「cannot dynamic_cast base_ptr (of type Base*) to type 'class Derived*' (Source type is not polymorphic)」のようなエラーが発生します。
サンプルコード
#include<iostream>
using namespace std;
class Base { };
class Derived: public Base {};
int main() {
Base *base_ptr = new Derived;
Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != NULL)
cout<<"It is working";
else
cout<<"cannot cast Base* to Derived*";
return 0;
}このエラーは、Baseクラスに仮想関数が存在しないことが原因です。dynamic_castはポリモーフィックな型(仮想関数を持つ型)にしか使用できないため、このような制限が発生します。
仮想関数を追加した場合の例
次に、Baseクラスに仮想関数を追加してみましょう。すると、同じコードでも正常に動作するようになります。
サンプルコード
#include<iostream>
using namespace std;
class Base {
virtual void function() {
//空の関数
}
};
class Derived: public Base {};
int main() {
Base *base_ptr = new Derived;
Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != NULL)
cout<<"It is working";
else
cout<<"cannot cast Base* to Derived*";
return 0;
}実行結果
It is working
補足:RTTIに関連する主な機能
C++のRTTIには、主に以下の2つの機能が含まれています。
- dynamic_cast演算子:基底クラスのポインタや参照を、安全に派生クラスの型へダウンキャストします。変換に失敗した場合、ポインタではnullptrが返され、参照ではstd::bad_cast例外がスローされます。
- typeid演算子:オブジェクトの実際の型情報をtype_infoオブジェクトとして取得でき、実行時の型比較に利用できます。
なお、RTTIを使用すると実行時の型チェックに伴うわずかなオーバーヘッドが発生するため、パフォーマンスが重視される場面ではコンパイラオプションで無効化されることもあります。設計の際には、その点も考慮しておくとよいでしょう。
-
C++における基底クラスと派生クラスの例外キャッチ:正しい順序の重要性
C++で基底クラスと派生クラスの両方の例外を捕捉したい場合は、派生クラスのcatchブロックを基底クラスのcatchブロックよりも必ず先に配置する必要があります。この順序を守らないと、派生クラスのcatchブロックは決して実行されず、常に基底クラス側が処理を引き受けてしまいます。これは、C++の例外処理が上から順に型の一致判定を行う仕組みになっているためです。派生クラスのオブジェクトは基底クラスの型としても扱えるため、基底クラスのcatchブロックが先にあると、そこで例外が捕捉されてしまうのです。アルゴリズムBegin クラスBを宣言する。 クラスBを継承する別のクラスDを宣言
-
C++のローカルクラスとは?特徴・制約と実装例をわかりやすく解説
ローカルクラスとは C++において、関数の中で宣言されたクラスは「ローカルクラス」と呼ばれます。これは、そのクラスが定義された関数の内部でのみ有効であるためです。 まず、ローカルクラスの基本的な構造を見てみましょう。 #include<iostream> using namespace std; void func() { class LocalClass { }; } int main() { return 0; } 上記の例では、関数 func() の中で LocalClass が定義されています。このように関数の内部で宣言されたクラスが、ローカルクラス