c++ typeid获取类型_c++ RTTI运行时类型识别

typeid 返回 std::type_info 类型的 const 引用,不可直接打印或字符串比较;常见错误是误用 cout

typeid 返回的是类型信息对象,不是字符串

调用 typeid 得到的是 std::type_info 类型的 const 引用,它不支持直接打印或比较字符串。常见错误是写 cout 期望输出类名,结果却是未定义行为或乱码——因为 std::type_info::name() 返回的是编译器特定的内部符号名(如 "St6vectorIiSaIiEE"),不是可读类型名。

  • 必须显式调用 .name() 才能获取 C 风格字符串指针
  • .name() 的返回值生命周期绑定到 type_info 对象,不能长期保存
  • 不同编译器对同一类型的 .name() 输出不同(GCC 是 mangled 名,MSVC 可能带空格和修饰)

开启 RTTI 后仍可能拿到不准确的类型名

即使编译时启用了 RTTI(-frtti / /GR),typeid 在多态场景下表现也受对象实际状态影响:

  • 对指针或引用使用 typeid(*ptr) 才能获得动态类型;typeid(ptr) 永远返回指针类型本身(如 "PKi"
  • 若对象是 nullptrtypeid(*ptr) 会抛出 std::bad_typeid 异常
  • 对于无虚函数的类,typeid 始终返回静态类型,无法反映继承关系中的实际类型
class Base {};
class Derived : public Base {};
Base b;
Derived d;
Base* p = &d;
cout << typeid(p).name() << endl;     // "P4Base"(指针类型)
cout << typeid(*p).name() << endl;     // "4Base"(静态类型,因 Base 无虚函数)

跨平台获取可读类型名需 demangle

要将 typeid(T).name() 转成类似 "std::vector" 的形式,必须调用 ABI 特定的 demangling 函数:

  • GCC/Clang:用 abi::__cxa_dem

    angle()
    ,需手动申请内存并释放
  • MSVC:typeid.name() 默认已 demangle,但含冗余空格和前缀(如 "class std::vector >"
  • 注意:demangle 结果不是标准保证,且 abi::__cxa_demangle 可能返回 nullptr(如输入非法)
#include 
int status;
char* demangled = abi::__cxa_demangle(typeid(std::vector).name(), 0, 0, &status);
if (status == 0) {
    cout << demangled << endl; // "std::vector >"
    free(demangled);
}

替代方案:用 constexpr 类型名比 typeid 更可靠

如果目标只是日志、断言或调试输出,typeid 的不可靠性和开销(RTTI 表、虚表查找)让它不如编译期方案:

  • C++20 可用 std::source_location::function_name() + 模板参数推导模拟类型名
  • 更通用的做法是用宏 + __PRETTY_FUNCTION____FUNCSIG__ 提取类型片段(例如 GCC 中 __PRETTY_FUNCTION__ 包含完整模板实参)
  • 第三方库如 Boost.TypeIndex 提供跨平台、可读、稳定的类型名接口,底层自动处理 demangle 和内存管理

真正需要运行时判断类型时,优先考虑虚函数 + dynamic_cast,而不是依赖 typeid().name() 字符串匹配——后者极易因编译器差异或优化级别变化而失效。