目次
低レイヤーのプログラミングとOS開発が趣味。C言語を使っています。
実行時型情報 RTTI
#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;
}
記事の執筆者にステッカーを贈る
有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。
さらに詳しく →Feedbacks
ログインするとコメントを投稿できます。
関連記事
- 競技プログラミングの基本処理チートシート (C++)限られた時間の中で問題を解くために必要となる、競技プログラミングにおける基本的な処理のチートシートです。競プロにおけるメジャー言語 C++ を利用します。その際 C++11 の機能は利用せず C++03 の機能の範囲内で記述します。 頻度高く定期的に開催されるコンテスト AtCoder Codeforces main.cpp #include <iostream>
- 構造体と列挙体 (C++をもう一度)構造体 #include <iostream> using namespace std; struct MyStruct { char charval; int intval; }; void Show(MyStruct* obj) { cout << obj->intval << endl; } int main() { ...
- Valgrind による C/C++ メモリリーク検出JVM メモリリークでは JDK の jstat や jmap で原因を調査できます。C/C++ では valgrind の Memcheck ツールが利用できます。valgrind には複数のツールが含まれており既定のツールが Memcheck です。他のツールを利用する場合は --tool オプションで指定します。 [簡単な利用例](h
- クラスの基本/初期化 (C++をもう一度)構造体のように初期化する (非推奨) #include <iostream> using namespace std; const int MAX_STR = 16; class MyClass { public: int m_integer; char m_str[MAX_STR + 1]; void Show(); }; void MyClass::Show...
- Union-Find サンプル『プログラミングコンテストでのデータ構造』で紹介されている Union-Find 木で集合を表現すると、以下のクエリを高速に実行できます。集合一つが一つの木となるため、複数の集合がある場合は全体として森になります。 ある要素 a_i と a_j が同じ集合に属しているかどうかの判定 二つの集合を一つの集合にまとめる サンプル [POJ 1182](https://translat