禁用 rtti 后 std::type_info 不可用,typeid 和 dynamic_cast 编译报错;因其依赖 vtable 中的类型信息指针,禁用后该指针被移除且 std::type_info 被定义为空类。

禁用 RTTI 后 std::type_info 会直接不可用
不能。只要编译器启用了 -fno-rtti(GCC/Clang)或 /GR-(MSVC),std::type_info 类型本身就会被定义为空类,所有依赖它的功能(比如 typeid 表达式、dynamic_cast)都会在编译期报错。
常见错误现象:
error: 'typeid' used on type 'X' with -fno-rttierror: 'std::type_info' has incomplete type-
undefined reference to 'typeinfo for X'(链接期,如果部分代码仍尝试引用)
为什么 typeid 和 std::type_info 必须依赖 RTTI
RTTI 不是可选的“附加信息”,而是整个机制的基础设施:typeid 运算符生成的 std::type_info 对象,其地址和内容由编译器在生成 vtable 时一并注入;禁用 RTTI 后,vtable 不再包含类型信息指针,std::type_info 的定义也被刻意留空(例如 libc++ 中变成 struct type_info {};)。
关键点:
立即学习“C++免费学习笔记(深入)”;
-
std::type_info的拷贝构造、赋值、operator==等成员函数,在无 RTTI 下全部被删除或未定义 - 即使你手动声明
extern "C" const std::type_info& __ti_X;,链接也会失败——符号根本不会生成 - 模板元编程中用
decltype或std::is_same_v替代运行时类型判断,才是正解
替代方案:不靠 RTTI 实现类型识别的常见做法
当必须禁用 RTTI(如嵌入式、游戏引擎底层、性能敏感路径),又需要某种“类型标识”能力时,有几种实际可行的替代方式:
- 为基类定义纯虚函数
virtual uint32_t type_id() const = 0;,子类返回 constexpr 哈希或枚举值 - 用
constexpr std::string_view name() { return "MyClass"; }配合编译期字符串哈希(如constexpr_hash("MyClass")) - 借助模板参数推导 +
static_cast,把类型选择逻辑移到编译期(例如 visitor 模式配合std::variant) - 若仅用于调试/日志,可用宏拼接
__PRETTY_FUNCTION__或__FUNCSIG__提取类型名字符串(注意长度和稳定性)
MSVC / GCC / Clang 在 -fno-rtti 下的行为差异
三者对 RTTI 的禁用是彻底且一致的,但错误提示细节略有不同:
- Clang/GCC:通常在使用
typeid时立刻报错,提示明确指向-fno-rtti - MSVC:
/GR-下typeid仍能通过编译,但生成的std::type_info对象恒为 null,调用其成员(如.name())会触发未定义行为(常表现为崩溃或空指针解引用) - 所有编译器下,
dynamic_cast在禁用 RTTI 时均被禁用,且不允许用于多态类型转换
真正容易被忽略的是:某些第三方库(如 Boost.TypeErasure、folly)内部可能隐式依赖 std::type_info,禁用 RTTI 后需确认其是否提供无 RTTI 构建选项。否则,链接阶段才暴露问题,排查成本更高。










