Baseクラスを派生したDeriv1クラスとDeriv2クラスがあるとします。Deriv1クラスの
インスタンスをnewして、Baseクラスのポインタ型変数に代入したはいいけど、それが
Deriv1クラスのインスタンスか、Deriv2クラスのインスタンスかを知りたい場合もあります。
このようにインスタンスがどのクラスのインスタンスかを調べなければいけないような
設計は良い設計とはいえません。しかし、調べられると便利な場合もあります。
このように動的に型情報を取得する機構を「実行時型情報(RTTI=Runtime Type Information」
といいます。
このRTTIを取得するクラスとして、「type_info」クラスがあります。このtype_infoクラスを
利用するには、「typeinfo」をインクルードする必要があります。
type_infoクラスのインスタンスを得るには、以下のようにtypeid演算子を使用します。
戻り値は、const type_infoの参照です。
const type_info& typeid(expression)
例)
int i;
typeid(i);
typeid(cout);
|
そして、type_infoクラスには以下のような公開関数があります。
type_infoクラスの主要な関数
関数名 |
書 式 |
説 明 |
operator== |
int operator==(const type_info& rhs) const |
2つのインスタンスを比較し、同じならば0以外が返ります。 |
operator!= |
int operator!=(const type_info& rhs) const |
2つのインスタンスを比較し、異なるならば0以外が返ります。 |
before |
int before(const type_info& rhs) const |
主に内部的に使用する関数なので、プログラマーにとってはあまり意味を持ちません。 |
name |
const char* name() const |
クラス名をNULL文字列として返します。 |
raw_name |
const char* raw_name() const |
主に内部的に使用する関数なので、プログラマーにとってはあまり意味を持ちません。 |
それでは簡単な例を紹介します。
#include<iostream>
#include<typeinfo>
using namespace std;
class Base{
public:
virtual void Test(){}
int a;
};
class Deriv : public Base{
public:
virtual void Test(){}
int b;
};
void main(){
Base* pBase = new Deriv();
int i;
// int型変数iの型は・・・
cout << typeid(i).name() << endl;
// 型を直接記述することもできる
cout << typeid(char).name() << endl;
// ポインタ型もOK
// ただし、Deriv*型にならないことに注意
cout << typeid(pBase).name() << endl;
// Base*型のインスタンスの中身はDerivクラスのインスタンス
cout << typeid(*pBase).name() << endl;
// pBaseの中のインスタンスがDerivクラスなのでtrueと表示
cout << (typeid(*pBase) == typeid(Deriv) ? "true" : "false") << endl;
delete pBase;
}
|
int
char
class Base *
class Deriv
true
|
仮想関数を含まないクラスでは静的結合になるため、RTTIも無効になります。
#include<iostream>
#include<typeinfo>
using namespace std;
class Base{
public:
// virtual void Test(){}
int a;
};
class Deriv : public Base{
public:
// virtual void Test(){}
int b;
};
void main(){
Base* pBase = new Deriv();
int i;
// ポインタ型もOK
// ただし、Deriv*型にならないことに注意
cout << typeid(pBase).name() << endl;
// Base*型のインスタンスの中身はDerivクラスのインスタンス
cout << typeid(*pBase).name() << endl;
// pBaseの中のインスタンスがDerivクラスなのでtrueと表示
cout << (typeid(*pBase) == typeid(Deriv) ? "true" : "false") << endl;
delete pBase;
}
|
class Base *
class Base
false
|
次に、テンプレートクラスの例を示します。
#include<iostream>
#include<typeinfo>
using namespace std;
template<class Type>
class Base{
public:
virtual void Test(){}
Type a;
};
template<class Type>
class Deriv : public Base<Type>{
public:
virtual void Test(){}
Type b;
};
void main(){
Deriv<int> intD;
Deriv<char> charD;
cout << "intD :" << typeid(intD) .name() << endl;
cout << "charD:" << typeid(charD).name() << endl;
cout << ( typeid(intD) == typeid(charD) ? "true" : "false" ) << endl;
}
|
intD :class Deriv<int>
charD:class Deriv<char>
false
|
上記の例のように、テンプレートでは、その両方とも同じでないと、同じクラスとは
認識しません。