typeid 返回 type_info 引用,不能直接用 == 比较;应使用 hash_code() 或 dynamic_cast;对多态对象需通过指针/引用解引用并确保基类有虚函数;空指针、悬垂引用等场景须预先检查。

typeid 返回的是 type_info 引用,不能直接用 == 比较两个对象
很多人写 typeid(obj1) == typeid(obj2) 看似能工作,但这是**未定义行为**——type_info::operator== 只保证对同一类型的多次调用返回相同结果,不保证不同类型的 type_info 对象地址或值可跨实例比较。实际中它常“碰巧”有效,尤其在单一编译单元里,但一旦涉及虚函数、动态链接库或优化级别变化,就可能失效。
正确做法是用 type_info::name() 或更稳妥的 type_info::hash_code():
-
typeid(a).hash_code() == typeid(b).hash_code()是标准保证的可靠比较方式(C++11 起) -
std::strcmp(typeid(a).name(), typeid(b).name()) == 0不推荐:名字格式由实现定义,可能带空格、模板参数缩写,且非 null-terminated(某些 MSVC 版本)
typeid 对多态对象默认只返回静态类型,要获取动态类型得用引用/指针
如果 Base* p = new Derived;,那么 typeid(p) 返回的是 Base* 的类型(即指针类型),而 typeid(*p) 才会触发 RTTI 查找真实类型——但前提是 Base 有至少一个虚函数(否则 RTTI 不启用,typeid(*p) 仍返回 Base)。
- 必须确保基类含虚函数(哪怕只是虚析构函数),否则
typeid(*ptr)永远不会返回派生类类型 - 传值调用会切片:
void f(Base b) { typeid(b); }中b已是纯Base对象,无法还原原始类型 - 推荐用
const Base&或Base*入参,再对解引用结果调用typeid
比较前必须确认对象是否为空指针或未定义状态
typeid(*nullptr) 是未定义行为,运行时大概率崩溃;同样,对未构造完成、已析构或内存越界的对象取 typeid 也会出问题。
- 对指针先判空:
if (p && typeid(*p).hash_code() == typeid(Derived{}).hash_code()) - 避免对局部对象取地址后在作用域外使用:
{ A a; ptr = &a; } → typeid(*ptr)是悬垂引用 - 容器中存储
std::any或std::variant时,应优先用它们自带的类型查询接口,而非裸typeid
替代方案:用 dynamic_cast 判断继承关系比 typeid 更实用
如果你真正想问的是“这个对象是不是某个具体子类”,dynamic_cast 比 typeid 更直接、更安全,也更符合 C++ 多态设计意图。
if (auto d = dynamic_cast<derived>(ptr)) { /* 它确实是 Derived */ }</derived>-
dynamic_cast自动处理空指针,失败返回nullptr(指针)或抛std::bad_cast(引用),无需手动防崩 - 若只需判断是否为某类型或其派生类,
dynamic_cast比typeid().hash_code()更贴近语义,且编译器优化友好
真正需要 typeid 的场景其实很少:比如做类型擦除容器的内部调度、调试打印类型名、或与外部系统约定 hash_code 映射。日常类型判断,别绕远路。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











