C++ のtype_info.name()
C++ではRTTIと呼ばれる機構によって,実行時の型情報が取得できる.
これによって,動的に定まるオブジェクトの型を知ることができる.
#include <typeinfo> #include <stdio.h> namespace test{ class A { public: virtual void m(){} // 1. 仮想メソッド宣言 }; class B : public A { public: virtual void m(){} // 1. 仮想メソッド宣言 }; } using namespace test; main(){ A * a0; a0 = new A(); const std::type_info & id = typeid(*a0); printf("%s\n", id.name()); a0 = new B(); const std::type_info & id2 = typeid(*a0); printf("%s\n", id2.name()); }
こんなコードを書いて,g++4.0で実行してみると
N4test1AE N4test1BE
という結果がでる.これらはtest::A, test:Bをマングリングしたものである.ちなみに,typeidは多相的な型でないとうまく機能しない.これは実行時型情報が典型的にはオブジェクトの仮想関数テーブルに収められるためである.例えば,上のコードで「仮想メソッド宣言」とコメントのついた2行を削除するとAとBは多相的でなくなるため,結果が変わってしまう.
N4test1AE N4test1AE
Visual C++では
type_info.name() で型の名前が取得できるが,この値のフォーマットは,仕様で規定されていない.従って,コンパイラ依存となっている.上記のコードをVisual C++ 2008 expressで実行すると,
class test::A class test::B
となる.したがって,コンパイラが異なるシステムで型情報をやりとりするには,このあたりをちゃんと吸収してやらなければならないわけだ.
マングリングとは
さて,g++で出てくる謎めいた文字列をどうやってデコードしたもんだろう? マングリングに関してはwikipediaにいい記事があった.が,コンパイラに非常に強く依存しているようなので,一筋縄では行かない.
どうせコンパイラに依存しているのであれば,コンパイラの提供しているライブラリを使えばいい,という説も.
こちらの記事によるとg++には__cxa_demangleという関数がありこれをつかえばよいとのこと.
extern "C" char *__cxa_demangle ( const char *mangled_name, char *output_buffer, size_t *length, int *status); std::string demangle(const char * name) { size_t len = strlen(name) + 256; char output_buffer[len]; int status = 0; return std::string( __cxa_demangle(name, output_buffer, &len, &status)); }
こうしておいて,
a0 = new A(); const std::type_info & id = typeid(*a0); printf("%s\n", demangle(id.name()).c_str());
こうすると
test::A
が得られる.めでたし?