typeid
演算子・type_info
型
実行時に型を調べるには演算子typeid
を使う.
if (typeid(obj1) == typeid(obj2)) { ... }
typeid
は,type_info
型のリファレンスを返すようになっている.
type_info
型は次のメソッドおよび演算子をもっていて,
上の例ではtype_info::operator==(const type_info&)
が呼ばれて同じ方かどうかを判定するという仕組みになっている.
type_info
は,ヘッダーファイルtypeinfo
で定義されている.
クラス名はtype_info
とアンダーバーが間にはいっているけど,
ヘッダーファイル名はtypeinfo
とアンダーバーがはいらないことに注意.
メソッド | 動作 |
---|---|
== |
同じ型かどうか判定する. |
!= |
異なる型かどうか判定する(== のNOT). |
before(rhs) |
処理系が使用しているオブジェクト配置順位(collation order)で,
*this オブジェクトがrhs より前に並んでいるかどうかを判定する.
いったいどういう用途で使うのか(かつ無害な使い方があるのか)疑問なメソッド….
|
name() |
オブジェクトの型を表現する文字列(たとえば“class C ”みたいな文字列)へのポインタを返す.
どんな文字列が返ってくるかは実装依存なので,name() が返してくる文字列をみて動作を変えるようなプログラムは好ましくない.
|
type_info
のクラス定義はだいたい次のような感じになっていると思われる.
class type_info { public: virtual ~type_info(); bool operator==(const type_info& rhs) const; bool operator!=(const type_info& rhs) const; bool before(const type_info& rhs) const; const char* name() const; private: type_info(const type_info&); const type_info& operator==(const type_info&); };
基本クラスのポインタとtypeid
を組み合わせて使い場合には少し気をつけなければならないポイントがある.
たとえば基本クラスB
からクラスD
が派生している場合,
B* obj = new D();
のように,基本クラスB
のポインタが,
派生クラスD
のインスタンスをさしているというような場合がある.
この場合,typeid(*obj)
は何を返すべきだろう?
たとえば,typeid(*obj).name()
としたら,“class B
”になるべきか,“class D
になるべきか?
正解は“class B
”で,たとえ全く同じインスタンスをさしているポインタ同士でも,
それぞれのポインタの型が違っていれば違うものと判定されてしまう.
直感的にはインスタンスの型を判定してほしいと思うんだけども….
たとえば,次のソースコードでは,typeid(*pobj1) == typeid(*pobj2)
は
同じインスタンスをさしているのにfalse
になってしまう.
class B { }; class D : public B { }; int main(void) { D* pobj1 = new D(); B* pobj2 = pobj1; if (typeid(*pobj1) == typeid(*pobj2)) // will be false cout << "same" << endl; else cout << "different" << endl; return 0; }
コード | 結果 | 備考 |
---|---|---|
typeid(*pobj1).name() |
class D |
|
typeid(*pobj2).name() |
class B |
まったく同じモノをさしているのにB* 経由だとclass B になる.
オブジェクトの本当の型(class D )が返ってくる仕様のほうが自然じゃないかと思う人もいるのでは?
|
typeid(pobj1).name() |
class D * |
おまけ(ここでの議論とはかんけいありません) |
もちろん,この動作が正しくないわけではなくて,typeid
で型を判定したのち,
型に応じてメソッドを呼び出すようなプログラムを書く場合,
この動作になってくれないと困るだろう(結局B*
の変数の場合,B
のもっているメソッドだけが呼び出せるわけだから).
ただ,この意味で使う目的ならtypeid
演算子って,むしろ廃止したほうがよかったのでは?とか思ったりもする….