typeid不能安全用于未定义行为表达式或非多态类型地址比较;应优先用dynamic_cast替代,因其更安全、语义清晰且支持空指针检查。

typeid 不能安全用于未定义行为的表达式,也不能在非多态类型上可靠比较地址 —— 这是 RTTI 最常被误用的两个起点。
typeid 的基本用法和限制
它返回 std::type_info 引用,但该对象不保证生命周期长于表达式求值;对临时对象或未求值表达式(如 typeid(int))可用,但对运行时多态对象必须确保对象有效。
- 对非多态类(无虚函数),
typeid(obj)返回编译期类型,不依赖实际对象内容 - 对多态类,
typeid(*ptr)才会触发动态类型查询;若ptr为空或指向已析构对象,行为未定义 -
typeid不支持比较不同编译单元中同名类型的type_info地址(可能重复实例化)
如何安全比较两个对象的动态类型
直接用 == 比较 typeid 结果看似简洁,但有陷阱:跨 DLL/so 时 type_info::name() 可能相同而地址不同,且 name() 不可移植(各编译器格式不同)。
class Base { virtual ~Base() = default; };
class Derived : public Base {};
Base ptr = new Derived();
if (typeid(ptr) == typeid(Derived)) { / 安全,因为 ptr 非空且多态 / }
// 危险示例:
Base bad_ptr = nullptr;
typeid(bad_ptr); // 未定义行为
替代方案:dynamic_cast + nullptr 检查更可靠
当目标是“判断能否转为某类型”时,dynamic_cast 比 typeid 更直观、更安全,且明确表达了意图。
立即学习“C++免费学习笔记(深入)”;
-
dynamic_cast返回非空指针表示成功,比字符串比对或地址比对更符合语义(ptr) - 不依赖 RTTI 开关(
-fno-rtti下typeid被禁用,但dynamic_cast同样失效) - 对引用类型抛异常,需
try/catch;指针版本则只返回nullptr,推荐优先使用
if (auto d = dynamic_cast(ptr)) { // 安全调用 Derived 特有接口 }
RTTI 性能与编译选项影响
启用 RTTI(默认开启)会为每个含虚函数的类生成 type_info 全局对象,并在虚表末尾附加类型信息指针。禁用(-fno-rtti)后:typeid 和 dynamic_cast 均不可用,链接时报错。
- 虚函数调用本身不受影响,RTTI 是独立机制
- 嵌入式或极致性能场景才考虑关闭;否则不要为省几字节放弃类型安全
- Clang/GCC 中,
typeid(T).hash_code()是稳定哈希值,可用于std::unordered_map键,比name()可靠
真正难处理的是跨模块类型识别 —— 此时连 hash_code() 都可能不一致,只能靠接口抽象或手动注册类型 ID。











