C++ :: typeidとdemangleで実行時クラス名取得

Javaでは普通に行われている実行時の型情報取得( Object.getClass(), Class.getName()とかinstanceOfとかね )ですが、CではできないのだからどうせC++でもできないのだろうなと思っていたら予想に反しRunTime Type Identification (RTTI)という実行時の型情報取得機能がばっちり用意されてました。 確かにdynamic_castができているわけだし、まあそういうことだよねと納得。 ということでC++で実行時クラス名の取得を試みました。

実行時型情報取得はtypeid演算子を使います。typeid演算子はtype_info型クラスの参照を返し、そのtype_infoのメンバname()より型情報の文字列が取得できます。 それでは次のコードで型情報を取得してみます。

#include <iostream>
#include <typeinfo>
using std::cout;
using std::endl;
using std::type_info;

class Parent{
public:
  virtual void x(){}
};
class Child : public Parent {};

main(){
    Parent* p;
    p = new Parent();
    const type_info & id_p = typeid(*p);
    cout << id_p.name() << endl;
    p = new Child();
    const type_info & id_c = typeid(*p);
    cout << id_c.name() << endl;
}

これをコンパイル(gcc 4.3.2)後に実行した結果は次のとおり。

6Parent
5Child

ParentクラスとChildクラスそれぞれの結果は確かにそれっぽいものが得られましたがなぜかクラス名の前に文字数がくっついてます。 どうしたもんだと思ってググってみるとまさにピンポイントなMLでの議論を発見。 クラスの前の数字がゴミに見えて気づかなかったのですがこれはマングリングされた文字列でした。 というわけで問題はデマングリングで解決します。上記MLではその法についても紹介されていたのでそれを参考にデマングリングを試みます。

デマングリングにはcxxabi.hに定義されている__cxa_demangle()関数を使用します。まずはヘッダを覗いてみます。

__cxa_demangle() @ /usr/include/c++/4.1.3/cxxabi.h

#ifdef __cplusplus
namespace __cxxabiv1
{
  extern "C"
  {
#endif
...略...
  // Demangling routines.
  char*
  __cxa_demangle(const char* __mangled_name, char* __output_buffer,
         size_t* __length, int* __status);
#ifdef __cplusplus
  }
} // namespace __cxxabiv1
#endif
...略...
// User programs should use the alias `abi'.
namespace abi = __cxxabiv1;

次にこの__cxa_demangle()を使って先のマングルされた文字列をデマングルしてみます。

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>
using std::cout;
using std::endl;
using std::type_info;

class Parent{
public:
  virtual void x(){}  // 1. 仮想メソッド宣言
};
class Child : public Parent {};

main(){
    Parent* p;
    int status;
    p = new Parent();
    const type_info & id_p = typeid(*p);
    cout << abi::__cxa_demangle(id_p.name(), 0, 0, &status) << endl;
    p = new Child();
    const type_info & id_c = typeid(*p);
    cout << abi::__cxa_demangle(id_c.name(), 0, 0, &status) << endl;
}

デマングル版コードをコンパイル(gcc 4.3.2)後に実行してみると無事クラス名が出力。 ということで見事実行時クラス名の取得に成功しました。

Parent
Child

おわり

Related posts:

  1. Dynamic Binding & VTable Concept in C++

Posted in: Programming / プログラミング

Tags: , ,



DeliciousFacebookRedditTwitterGoogle

addLeave a comment