RTTI 开销主要来自type_info存储、vtable扩展和dynamic_cast运行时检查;其中dynamic_cast在多继承或虚继承时可达O(N),而type_info内存开销虽单个很小但随类数量累积,vtable附加指针可能影响缓存局部性。

RTTI 的开销主要来自类型信息存储、虚函数表扩展和运行时类型检查逻辑,dynamic_cast 是其中最重的操作,尤其在多继承或深层继承链中。
类型信息(type_info)的内存开销
每个含虚函数的类都会生成一个 type_info 对象,由编译器静态生成并存于只读数据段。单个 type_info 很小(通常几十字节),但项目中类数量多时会累积占用可观的常量内存。启用 RTTI 后,即使没用 dynamic_cast,这些信息也存在——无法按需剥离。
dynamic_cast 的时间开销来源
它不是简单查表,而是依赖运行时遍历类的继承关系:
- 单继承且目标类型是直接/间接基类:通常只需沿虚表向上跳转,接近 O(1);
- 多继承下跨分支转换(如从左基类转到右基类):需遍历 std::type_info 关联的继承图谱,可能 O(N),N 是继承层级深度或兄弟基类数;
- 涉及虚继承时:查找路径更复杂,部分实现需回溯或缓存辅助结构,开销明显上升;
- 失败的 dynamic_cast
或指针转换:仍要走完整检查流程,不提前退出。
虚函数表(vtable)的隐式膨胀
开启 RTTI 后,编译器会在 vtable 末尾附加指向 type_info 的指针(每个含虚函数的类一份)。这本身不增加调用开销,但会使 vtable 变长,可能轻微影响 CPU 缓存局部性——尤其在大量小类、频繁虚调用的场景中。
立即学习“C++免费学习笔记(深入)”;
可规避的典型误用
不少性能问题其实源于设计而非 RTTI 本身:
- 在热循环里反复 dynamic_cast 同一对象 → 应缓存转换结果或改用访问者模式;
- 用 dynamic_cast 判断类型再分发行为 → 更好方式是用虚函数多态或 std::variant(C++17);
- 仅用于调试断言(如 assert(dynamic_cast
(p)))→ 可用 NDEBUG 宏条件编译剔除; - 整个模块无需 RTTI(如嵌入式、游戏引擎核心)→ 用 -fno-rtti 彻底禁用,链接器还能删掉相关符号。
基本上就这些。RTTI 本身不昂贵,但 dynamic_cast 在复杂继承结构中容易成为隐藏瓶颈——关键不在“用不用”,而在“在哪用、怎么用”。











