标准rtti在嵌入式、游戏引擎等场景不足,因其依赖编译器只读类型信息,无法运行时注册新类型或跨模块可靠工作;需用函数地址作typeid、显式注册继承关系及偏移量来实现可控、可扩展、可序列化的类型系统。

为什么标准 typeid 和 dynamic_cast 不够用
嵌入式环境、游戏引擎或热重载系统中,标准 RTTI 常被禁用(-fno-rtti),因为它的类型信息是编译器生成的只读段数据,无法在运行时注册新类型,也不能跨 DLL/so 边界可靠工作。你真正需要的不是“模拟 typeid”,而是可控、可扩展、可序列化的类型标识与转换能力。
用 std::type_info 替代方案:手写 TypeID 类
核心是把类型唯一性从编译器手里拿回来——用地址、哈希或字符串做 ID,再配一个全局注册表。最轻量且无冲突的做法是用函数地址作 ID:
struct TypeID {
constexpr TypeID() : value(nullptr) {}
explicit constexpr TypeID(void (*f)()) : value(f) {}
const void* value;
bool operator==(const TypeID& other) const { return value == other.value; }
bool operator!=(const TypeID& other) const { return value != other.value; }
};
<p>template<typename t>
constexpr TypeID type_id_of() {
// 每个 T 对应唯一函数地址,无需定义,仅取址
return TypeID(+[]{}); // lambda 地址随类型变化,且不产生 ODR 违规
}
</typename></p>
注意:+[]{} 强制取 lambda 的函数指针,不同模板实例化出的 lambda 地址必然不同,且不依赖静态存储期——比用 &T::static_func 更安全,也比 __PRETTY_FUNCTION__ 字符串哈希更高效。
如何实现 is_same_type 和 cast_to 逻辑
类型比较直接用 TypeID 比对;向下转型则需维护继承关系。不要尝试模拟 vtable 偏移计算——太脆弱。改用显式注册的映射表:
- 每个派生类在构造时调用
register_inheritance(&Base::type_id, &Derived::type_id) -
cast_to<base>(ptr)先查ptr的实际TypeID,再查该 ID 是否在Base的可转类型集合中 - 若匹配成功,执行
static_cast(你已保证继承关系合法) - 不支持多重继承自动路径推导;必须显式注册每条路径,比如
A → B、A → C、B → D,否则D*到A*会失败
示例片段:
class Base {
public:
static TypeID type_id;
virtual ~Base() = default;
};
TypeID Base::type_id = type_id_of<base>();
<p>class Derived : public Base {
public:
static TypeID type_id;
};
TypeID Derived::type_id = type_id_of<derived>();</derived></p><p>// 注册:Derived 可安全转为 Base
static auto _ = register_inheritance(Derived::type_id, Base::type_id);
</p>
指针转换时最容易忽略的内存布局问题
即使类型关系注册正确,static_cast 仍可能出错——尤其涉及虚继承或非首基类时。你的 cast_to 函数不能只返回 static_cast<t>(ptr)</t>,而应封装一层校验:
- 若目标类型与源类型相同,直接返回
ptr - 若存在单继承路径,且目标是源类型的某个基类,用
reinterpret_cast+ 偏移量(需提前注册偏移)更稳妥 - 推荐做法:在注册继承关系时,同时存下
offset_from_derived_to_base,比如offsetof(Derived, Base),避免运行时依赖 ABI - 永远不要对未定义析构函数的对象做向上转型后 delete——你的系统不控制对象生命周期,这点和标准
dynamic_cast一致但更不透明
真正难的不是写出能跑的代码,而是让团队所有人记得每次加新类都要注册继承、更新偏移、同步跨模块的 TypeID 表——漏一条,调试时就是静默转型失败。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











