23章 実行時型情報 RTTI

http://www.geocities.jp/ky_webid/cpp/language/023.html

なんか名前はややこしそうですが、内容はそうでもないです。

RTTIとはRun-Time Type Identificationの略であり、実行時型情報といいます。

あるポインタ変数が、何の型なのかを取得することができます。

C++ではあるクラスを継承したクラスを使うことによって多態性を実現できます。

したがってあるポインタ変数に入ってるデータが何のクラスの型かわからないのです。

それを実行時に取得するのがtypeid演算子というものになります。

実際に動かしてみましょう。

#include <iostream>
using namespace std;

class CSampleBase {
public:
    virtual ~CSampleBase() {}
};

class CSampleA : public CSampleBase {
};

class CSampleB : public CSampleBase {
};

int main () {
    CSampleBase* pBase = new CSampleBase;
    CSampleBase* pA = new CSampleA;
    CSampleBase* pB = new CSampleB;
    
    cout << typeid(*pBase).name() << endl;
    cout << typeid(*pA).name() << endl;
    cout << typeid(*pB).name() << endl;
    
    return 0;
}
$ main
class CSampleBase
class CSampleA
class CSampleB

うまく表示できていますね。コンパイルオプションに/GRが必要と書いていましたがVC2008の環境では無しでも動きました。

さてここでひとつ問題です。基底クラスに仮想デストラクタを持っていますね。もしこれを書いてないと実行結果が下記のようになります。

$ main
class CSampleBase
class CSampleBase
class CSampleBase

何故こうなるかというのは、継承のところでチラッと習いました。

仮想関数がひとつもないクラスの場合を宣言すると、静的結合と呼ばれる扱いになります。また仮想関数がひとつでもあれば動的結合になります。

静的結合になるとそのクラスで呼び出されたメンバ関数は、どんな場合でもそのクラスのものとなります。

typeid演算子で型を調べる際には、その対象のクラスが動的結合されていないと正常に動かないのです。

つまり最低ひとつは仮想関数を定義しなければなりません。

そこで上記の例ではデストラクタを仮想化しているということになります。

もちろん

virtual void foo () {}

のような仮想関数を用意すれば仮想デストラクタは必要なくなりますが、動的結合にしたいだけの理由でわざわざfoo関数を定義するのは馬鹿らしいので特に何もメンバ関数を用意する必要がないような場合、仮想デストラクタが良く使われるということなんですね。

もちろん、仮想デストラクタが必要な理由はまだあります。

が、今回とは話がズレるのでまた別の機会に。