#include <iostream>
#include <typeinfo>
using namespace std;
class MyClass {
public:
virtual ~MyClass() {} // typeid で正しい RTTI
// (RunTime Type Information; 実行時型情報)
// を得るためには少なくとも virtual 仮想関数が
// 一つ存在することが必要です。エラーが出ずに
// 正しい値が得られないだけなため、はまりどころです。
// (開発環境によっては更に RTTI をオプションで有効化
// しなければならないこともあります)
};
class MySubClassA :
public MyClass
{
};
class MySubClassB :
public MyClass
{
};
void MyFunc(const MyClass& obj) {
const type_info& ti = typeid(obj);
cout << ti.name() << endl; //=> 11MySubClassA
// 真偽を true/false 文字列で出力 (マニピュレータ)
cout << boolalpha;
cout << (ti == typeid(MyClass)) << endl; //=> false
cout << (ti == typeid(MySubClassA)) << endl;
//=> true (← アップキャスト前の型が判明)
cout << (ti == typeid(MySubClassB)) << endl; //=> false
}
int main() {
MySubClassA obj;
MyFunc(obj);
return 0;
}
実行時型情報 RTTI を頼りに、継承木の下へのキャスト (ダウンキャスト) の正しさを調査できます。dynamic_cast はアップキャストやダウンキャスト (あるいはそれらを同時に行うクロスキャスト) という、継承木におけるあるノードから別のノードへのキャストを行うために存在しています。ダウンキャスト時にはその正しさの調査を自動で行い、不正なダウンキャストに対しては例外などで知らせてくれます。アップキャスト時には正しさの調査を行う必要もないことから、わざわざ dynamic_cast を使用する利点はあまりないですが文法上は可能です。
dynamic_cast は static_cast にダウンキャストの成功判定機能やクロスキャスト機能を付け加えたようなものであり、本質的には static_cast でも同じことが実現できます。しかしながら、ダウンキャストは危険なキャストなため、処理速度がよほど気になる場合を除き、継承木キャスト専用の dynamic_cast を使用するようにしましょう。
#include <iostream>
#include <typeinfo>
using namespace std;
class MyClass {
public:
virtual ~MyClass() {}
};
class MySubClassA :
public MyClass
{
};
class MySubClassB :
public MyClass
{
};
void MyFunc(const MyClass& obj) {
try {
const MySubClassA& objA = dynamic_cast<const MySubClassA&>(obj); // 成功
const MySubClassB& objB = dynamic_cast<const MySubClassB&>(obj); // 失敗 (=> bad_cast 例外)
}
catch(const bad_cast& e) {
cerr << "bad_cast" << endl; // typeinfo で定義されています
}
// ポインタの dynamic_cast では例外ではなく NULL が返ります
const MySubClassA* ptrA = dynamic_cast<const MySubClassA*>(&obj);
const MySubClassB* ptrB = dynamic_cast<const MySubClassB*>(&obj);
if ( ptrA == NULL ) {
cerr << "ptrA == NULL" << endl;
}
if ( ptrB == NULL ) {
cerr << "ptrB == NULL" << endl;
}
}
int main() {
MySubClassA obj;
MyFunc(obj); //=> bad_cast
// ptrB == NULL
return 0;
}