This question is for MSVC ABI non-portable materials.
I am trying to write the C ++ equivalent typeidin explicitly non-portable, but not magical C ++. For Itanium ABI (as used on Linux / Mac) it is very simple:
const std::type_info& dynamicast_typeid(void *mdo)
{
std::type_info **vptr = *reinterpret_cast<std::type_info ***>(mdo);
std::type_info *typeinfo_ptr = vptr[-1];
return *typeinfo_ptr;
}
So, now I look at the 64-bit MSVC ABI, and I am stunned. For very simple classes that start with vfptr with an offset of 0, it's almost as easy as Itanium:
const std::type_info& dynamicast_typeid(void *mdo)
{
int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];
char *result = (char *) rtti_complete_object_locator;
result -= rtti_complete_object_locator[5];
result += rtti_complete_object_locator[3];
return *(std::type_info*)result;
}
(This code is based on the Wine project__RTtypeid .)
The problem is that some C ++ classes do not start with vfptr at offset 0! Sometimes they start with vbptr.
struct Class1 { virtual ~Class1() {} };
struct Class2 : virtual Class1 {};
Class1starts with vfptr; Class2starts with vbptr.
vbptr, , ( , , " " ) vfptr 0. , , , vbptr, :
const std::type_info& dynamicast_typeid_for_vbptr_class(void *mdo)
{
int first_vbase_offset = ((int**)mdo)[0][1];
mdo = (char*)mdo + first_vbase_offset;
int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];
char *result = (char *) rtti_complete_object_locator;
result -= rtti_complete_object_locator[5];
result += rtti_complete_object_locator[3];
return *(std::type_info*)result;
}
, MSVC
if constexpr(IS_VBPTR_CLASS) {
int first_vbase_offset = ((int**)mdo)[0][1];
mdo = (char*)mdo + first_vbase_offset;
}
return __RTtypeid(mdo);
++ typeid(x) - IS_VBPTR_CLASS ", , x vbptr x , ."
x, , , ( ++, ), x vbptr .
,
const std::type_info& dynamicast_typeid(void *mdo)
{
while (((int**)mdo)[0][0] == 0) {
mdo = (char *)mdo + ((int**)mdo)[0][1];
}
int *rtti_complete_object_locator = ((int ***)mdo)[0][-1];
char *result = (char *)complete_object_locator;
result -= rtti_complete_object_locator[5];
result += rtti_complete_object_locator[3];
return *(std::type_info*)result;
}
, info, vftable Class1 2, info Class1, Class2! .
, : (void*)&object_of_type_class2, typeid(Class2)?