typeid 的 name() 字符串不可直接比较,因 gcc/clang 返回 mangled 名(如 "n12mynamespace7myclasse"),msvc 类似,需用 abi::__cxa_demangle 或 __undname 解码且手动释放内存;多态识别需基类含虚函数(如虚析构);跨平台应优先使用 hash_code() 作类型标识。

typeid 返回的 name() 字符串不可直接比较
用 typeid(obj).name() 拿到的名字是编译器实现相关的,GCC/Clang 返回的是 mangled 名(比如 "N12MyNamespace7MyClassE"),MSVC 也类似,不是可读字符串。直接拿它做 == 判断或日志输出,大概率出错或看不懂。
- 需要先调用
abi::__cxa_demangle()(GCC/Clang)或__unDName()(MSVC)解码,否则看到的不是类名 - 解码后内存需手动
free(),漏掉会内存泄漏 - 跨平台项目里,最好封装一层适配逻辑,别裸用
name()
typeid 在多态对象上必须配合虚函数才能动态识别
如果类没有虚函数(即无虚表),typeid 对指针或引用永远返回静态类型,而不是实际对象类型。这是最容易被忽略的前提条件。
- 哪怕子类重写了函数,只要基类没至少一个虚函数(包括虚析构),
typeid(*ptr)就不会“看穿”指针真实指向的子类 - 典型错误:把
Base*指向Derived实例,却期望typeid(*ptr).name()返回Derived的名字——不加虚函数就做不到 - 最小代价:给基类加个虚析构函数
virtual ~Base() = default;,就能激活 RTTI 的动态行为
std::type_info::hash_code() 是唯一可移植的类型标识方式
比起不可靠的 name(),typeid(T).hash_code() 是标准规定的稳定值,同一程序中相同类型一定相等,不同类型大概率不等,适合做类型 ID 缓存或 switch 分支。
- 比字符串比较快,无内存分配、无解码开销
- 不能跨进程/跨 DLL 使用(哈希值不保证全局一致),但本进程内绝对可靠
- 可用于 unordered_map 的 key:比如
std::unordered_map<:size_t std::any> type_registry;</:size_t>,key 用typeid(X).hash_code()
开启 RTTI 是 typeid 正常工作的前提
某些嵌入式或性能敏感项目会用 -fno-rtti 关闭运行时类型信息,此时所有 typeid 表达式都会编译失败(GCC/Clang 报错 ‘typeid’ used on polymorphic type ‘X’ with /RTTI- disabled)。
立即学习“C++免费学习笔记(深入)”;
- 检查编译选项:CMake 中确认没设
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") - MSVC 对应开关是
/GR-,要确保是/GR(默认开启) - 关了 RTTI 后,不仅
typeid不可用,dynamic_cast也会失效——这两者是一体的机制
类型名称这件事,本质是编译器和 ABI 协作的结果,不是语言层的“字符串反射”。真正稳定可用的只有 hash_code(),其余都得绕着 mangling 和虚表走。别指望靠 name() 做类型判断逻辑,尤其在发版前没在目标平台上实测解码结果的话。










