手动实现一个RTTI系统
在 C++ 中,RTTI(Runtime Type Information,运行时类型信息)是一组允许程序在运行时获取对象类型信息的机制 。虽然C++通过虚接口的方式提供了良好的抽象,但是对于一个复杂的系统,过于依赖抽象而忽略业务的复杂性,隐藏类的具体运行时信息,往往让业务变得不够灵活,或者大大增加虚接口的代价。
标准 C++ RTTI 的组成
typeid
运算符
可以通过typeid函数获取对象的实际类型信息。其返回值为std::type_info
对象,包含类型名称和对比功能。
Base* obj = new Derived();
// 获取静态类型信息(编译时确定)
std::cout << typeid(*obj).name() << std::endl; // 输出 "Derived"(若启用 RTTI)
// 类型对比
if (typeid(*obj) == typeid(Derived)) {
// 实际类型为 Derived
}
dynamic_cast
C++提供的安全类型转换,安全地将基类指针/引用转为派生类指针/引用。但是要求基类必须有虚函数(即多态类型)。指针类型转换失败返回 nullptr
,引用类型转换失败抛出 std::bad_cast
。
type_info
类
存储类型信息,提供 name()
和 operator==
。只能通过 typeid
获取其实例。
C++标准虽然提供了一些简单的RTTI功能,但是存在一些缺点
dynamic_cast
的运行时类型检查可能影响性能(尤其深继承层次)。type_info::name()
返回的名称是编译器修饰后的(如7Derived
)。dynamic_cast
仅适用于有虚函数的类。- 无法添加自定义类型元数据(如版本号、作者等)
不过,用户可以选择启用或者禁用RTTI功能,如果禁用后,就无法使用上面提到的功能,并且值得强调的时,C++RTTI其实是有点违背C++的Zero over head的设计哲学,开启 RTTI 后,所有多态类会携带一个虚表指针 (vptr
),指向包含 type_info
的虚表。即使开发者完全不使用 RTTI,这一内存开销仍然存在。type_info
对象和类型名称字符串会被编译进程序,增加可执行文件
自定义RTTI系统
针对标准 RTTI 的不足,开发者常实现自定义 RTTI 系统 , RTTI系统实现的原理也非常简单
- 定义一个MetaClass用于表示类的元信息
- 每个类使用一个静态的MetaClass存储该类形的信息
- 实现一些常用的如类型名称,类型转换,类型实例化等接口
如下为手动实现的RTTI系统的一些关键组件
元类(MetaClass)
封装类的类型信息,包括类名、父类元类指针、对象构造函数。
关键方法:
isKindOf
:递归检查当前类是否继承自指定父类。create
:通过绑定的构造函数创建对象。
class MetaClass {
public:
MetaClass(std::string name, const MetaClass* pParent, ObjectConstructor cons);
bool isKindOf(const MetaClass* pParent) const; // 继承关系检查
MetaObject* create(); // 创建对象
private:
std::string m_name;
const MetaClass* mp_parent;
ObjectConstructor m_constructor;
};
模板元类(ConcretMeta)为具体类生成元类实例,自动注册到 MetaClassStore
。这里使用单例的方式来获取类的MetaClass
template <class T>
class ConcretMeta : public MetaClass {
public:
static const MetaClass* instance() {
static ConcretMeta s_meta;
MetaClassStore::instance()->insert(&s_meta);
return &s_meta;
}
private:
ConcretMeta() : MetaClass(T::class_name(), ConcretMeta<T::BaseClass>::instance(), [] { return new T(); }) {}
};
对象基类(MetaObject)
所有需要有RTTI能力的类需要继承自MetaObject,该类定义了获取MetaClass的接口和其他类型转换接口。
class MetaObject
{
public:
virtual ~MetaObject() = 0;
virtual const MetaClass* meta() const = 0; //called by instance
static const MetaClass* staic_meta(); //called by class
static MetaObject* meta_cast(MetaObject* pOther);
static std::string class_name();
bool isKindOf(const MetaClass* pMeta) const;
public:
MetaObject() = default;
};
RTTI定义宏系统
DECLARE_META_CLASS
:声明元类接口。DEFINE_META_CLASS
:实现元类绑定和类型转换。
// 声明.h
class MyClass : public MetaObject {
DECLARE_META_CLASS(MyClass, MetaObject);
};
// 定义.cpp
DEFINE_META_CLASS(MyClass, MetaObject);
该 RTTI 系统通过模板和宏巧妙地将类型信息抽象为运行时对象,实现了类型创建、继承检查和简单反射功能。设计简洁且易于扩展,可作为复杂对象工厂或序列化系统的基础组件。