返回目录
在研究过VC的RTTI的基本结构之后,我们先来看看最简单的 typeid是怎么实现的。
在VC中,当你对多态类的指针ptr使用 typeid(*ptr)之后,编译器会做两件事情:首先是将指针进行调整,使它指向当前类的vftable处(注意,类的vftable未必处在类的开始),然后再调用__RTtypeid,返回type_info对象。我们可以试验一下下面的代码。
template<typename T>
const type_info &GetTypeID(const T *obj)
{
if (typeid(*obj)==*__RTtypeid(obj))
return typeid(*obj);
else
throw new std::bad_typeid("...");
}
template<typename T>
const TypeDescriptor *__RTtypeid(const T *ptr)
{
if (!ptr) throw new std::bad_typeid("Attempted a typeid of NULL pointer!");
const _s_RTTICompleteObjectLocator *pCompleteLocator=GetCompleteObjectLocator(ptr);
TypeDescriptor *pTypeDescriptor=pCompleteLocator->pTypeDescriptor;
if (!pTypeDescriptor) {
throw std::__non_rtti_object("Bad read pointer - no RTTI data!");
}
return pTypeDescriptor;
}
可以看到, typeid的实现很简单。
这是因为编译器会在类的vftable(包括它自己的和从基类继承的)的第一个函数指针前面插入一个指向_s_RTTICompleteObjectLocator结构的指针,这个结构中会存放该类的TypeDescriptor(上面的GetCompleteObjectLocator函数就是用来从vftable获得s_RTTICompleteObjectLocator结构的)。因此,即使你将派生类的指针赋给基类的指针,你仍然可以利用上面的算法得到派生类的类型。
在研究过VC的RTTI的基本结构之后,我们先来看看最简单的 typeid是怎么实现的。
在VC中,当你对多态类的指针ptr使用 typeid(*ptr)之后,编译器会做两件事情:首先是将指针进行调整,使它指向当前类的vftable处(注意,类的vftable未必处在类的开始),然后再调用__RTtypeid,返回type_info对象。我们可以试验一下下面的代码。
template<typename T>
const type_info &GetTypeID(const T *obj)
{
if (typeid(*obj)==*__RTtypeid(obj))
return typeid(*obj);
else
throw new std::bad_typeid("...");
}
template<typename T>
const TypeDescriptor *__RTtypeid(const T *ptr)
{
if (!ptr) throw new std::bad_typeid("Attempted a typeid of NULL pointer!");
const _s_RTTICompleteObjectLocator *pCompleteLocator=GetCompleteObjectLocator(ptr);
TypeDescriptor *pTypeDescriptor=pCompleteLocator->pTypeDescriptor;
if (!pTypeDescriptor) {
throw std::__non_rtti_object("Bad read pointer - no RTTI data!");
}
return pTypeDescriptor;
}
可以看到, typeid的实现很简单。
这是因为编译器会在类的vftable(包括它自己的和从基类继承的)的第一个函数指针前面插入一个指向_s_RTTICompleteObjectLocator结构的指针,这个结构中会存放该类的TypeDescriptor(上面的GetCompleteObjectLocator函数就是用来从vftable获得s_RTTICompleteObjectLocator结构的)。因此,即使你将派生类的指针赋给基类的指针,你仍然可以利用上面的算法得到派生类的类型。