C++无原生反射,但可通过RTTI(typeid、dynamic_cast)实现类型识别与安全转换,结合宏辅助的手写反射系统或C++20编译期反射草案达成实用反射能力。

C++ 本身不提供像 Java 或 C# 那样的原生反射(reflection)机制,即无法在运行时自动枚举类的成员变量、方法、注解等完整结构信息。但通过 RTTI(Run-Time Type Information) 和一些手动/半自动的工程实践,可以实现**有限但实用的反射能力**——重点是类型识别、安全类型转换和基础元信息支持。
RTTI 是什么?能做什么?
RTTI 是 C++ 标准提供的运行时类型查询设施,核心组件包括:
-
typeid 操作符:获取对象或类型的 type_info 引用,可用于比较类型是否相同(如
typeid(a) == typeid(b)); - dynamic_cast:在继承体系中进行安全的向下转型(downcast),失败时返回 null(指针)或抛出 std::bad_cast(引用)。
注意:typeid 和 dynamic_cast 仅对**含虚函数的多态类型**生效(编译器需生成虚表和 RTTI 数据)。普通 struct/class 若无虚函数,默认不启用 RTTI(GCC/Clang 可用 -fno-rtti 关闭,此时使用会报错)。
用 RTTI 实现基础反射能力
虽然不能直接列出字段,但可结合约定+辅助结构模拟反射行为:
立即学习“C++免费学习笔记(深入)”;
-
类型名字符串化:用
typeid(T).name()获取编译器生成的类型名(通常为 mangled 名,可用abi::__cxa_demangle解析成可读名); -
运行时类型判别与分发:比如序列化框架中,根据
typeid(obj)选择对应序列化函数; -
安全工厂/克隆:基类定义虚函数
virtual std::unique_ptr,派生类实现,配合clone() const = 0 dynamic_cast验证返回类型。
手写轻量级反射系统(推荐实践)
真正实用的 C++ 反射往往靠“人工注册 + 宏辅助”实现。例如:
- 为每个需反射的类定义静态成员函数,返回字段名、偏移、类型 ID 等元数据;
- 用宏(如
REFLECTABLE(x, y, z))自动生成注册代码,减少重复; - 搭配 std::any / std::variant 存储任意字段值,用字符串名访问(如
obj.get);("age") - 开源库参考:nlohmann/json 的
to_json/from_json特化、magic_enum(枚举反射)、Boost.Hana(编译期反射)。
现代替代方案:编译期反射(C++20 及以后)
C++20 引入了 反射 TS(Technical Specification)草案,虽未正式进入标准,但 Clang 已实验性支持(需 -std=c++2b -freflections)。它允许:
-
reflexpr(T)获取类型的编译期描述; - 遍历基类、成员、模板参数等;
- 生成字段名字符串、构造默认值等。
当前仍属前沿,生产项目慎用;但代表了 C++ 反射的未来方向——无需宏、无需运行时开销、类型安全。
不复杂但容易忽略:RTTI 是反射的起点而非终点,真正的反射能力需要你主动设计元数据模型,并在类型定义与工具链之间建立契约。











