RTTI在C++中依赖编译器开关(如GCC/Clang的-fno-rtti、MSVC的/GR-)和代码配合启用;dynamic_cast、typeid、type_info仅在RTTI开启且目标类为多态类型时有效。

RTTI在C++里靠什么启用
C++的RTTI功能不是默认全开的——它依赖编译器开关和代码层面的配合。关键点是:dynamic_cast、typeid 和 type_info 这三者只有在启用了RTTI支持时才可用,否则链接会失败或行为未定义。
- GCC/Clang 默认开启RTTI,但可通过
-fno-rtti关掉;一旦关了,dynamic_cast会退化为static_cast(无运行时检查),typeid对非多态类型仍可用,但对多态类型将报错 - MSVC 默认也开,对应开关是
/GR(开启)或/GR-(关闭) - 即使编译器开了RTTI,
dynamic_cast仍要求目标类至少有一个虚函数(即必须是多态类型),否则编译直接报错:error: cannot dynamic_cast ... (source type is not polymorphic)
用dynamic_cast做安全向下转型
这是RTTI最常用也最容易出错的场景:把基类指针/引用转成派生类类型。
- 必须确保源对象实际是目标类型,否则
dynamic_cast返回nullptr(指针)或抛出std::bad_cast(引用) - 只对指针和引用有效,不能用于内置类型或普通对象(值类型)
class Base { virtual ~Base() = default; };
class Derived : public Base {};
<p>Base<em> b = new Derived;
Derived</em> d = dynamic_cast<Derived<em>>(b); // ✅ 成功,d 指向原对象
Base</em> b2 = new Base;
Derived<em> d2 = dynamic_cast<Derived</em>>(b2); // ❌ 失败,d2 == nullptr
常见坑:
- 忘记检查返回值,直接解引用
nullptr导致崩溃 - 对非多态基类(没虚函数)使用
dynamic_cast,编译不过 - 在模板中误以为
dynamic_cast能推导类型,其实它不参与SFINAE,失败时是运行时错误而非编译期丢弃
typeid比较类型是否相同
typeid 返回 const std::type_info&,可用于判断两个对象是否为同一类型(注意:仅对多态类型能反映真实动态类型)。
立即学习“C++免费学习笔记(深入)”;
- 对非多态类型,
typeid返回的是静态类型(即变量声明类型) - 对多态类型,
typeid返回运行时实际类型(即new Derived的对象,即使通过Base<em></em>访问,typeid(ptr)仍是Derived)
Base* b = new Derived;
std::cout << (typeid(*b) == typeid(Derived{})) << "\n"; // true
std::cout << (typeid(*b) == typeid(Base{})) << "\n"; // false
<p>int x = 42;
std::cout << (typeid(x) == typeid(long)) << "\n"; // false —— 静态类型决定
注意事项:
-
typeid表达式不能作用于不完整类型(如前置声明类) - 比较结果依赖编译器实现(但标准保证同一程序内相同类型有相同
type_info地址) - 不要依赖
type_info::name()做字符串匹配——它未标准化,GCC输出可能是 mangled 名
RTTI的性能与替代思路
RTTI不是零成本:每次 dynamic_cast 或 typeid 都需查虚表、遍历继承链,尤其在深度多重继承下可能明显拖慢。
- 如果你只做“是不是A或B”,且类型集合固定,考虑用虚函数返回枚举(
enum class Type { A, B, C };+virtual Type type() const),比dynamic_cast快且可控 - 游戏引擎或嵌入式环境常禁用RTTI(
-fno-rtti),此时dynamic_cast不可用,typeid功能受限,必须提前规划类型识别方案 -
std::any和std::variant是现代C++中更类型安全、且不依赖RTTI的替代选择,但语义不同(前者擦除类型,后者限定类型集合)
RTTI本身不难启用,真正容易被忽略的是:它只对多态类型生效,且所有检查都发生在运行时——这意味着类型错误不会在编译期暴露,调试时得靠日志或断言兜底。


















