C++不同平台下的RTTI实现
给定一个含有虚函数的对象的地址,找到对应的类名,不同平台下方法也不同,这是由于RTTI实现并没有统一的标准。
Linux:
#include <iostream>
#include <typeinfo>
class Person
{
public:
virtual void func()
{
std::cout << typeid(*this).name() << std::endl;
}
};
const char* ClassName(void* address)
{
uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);
uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);
std::type_info* ti = reinterpret_cast<std::type_info*>(*(vftablePtr - 1));
return ti->name();
}
int main()
{
Person p;
std::cout << ClassName(&p) << std::endl;
std::cout << typeid(p).name() << std::endl;
}
运行结果:
6Person
6Person
其中,Person
代表类名,6
表示的是类名的长度。
Windows x86:
#include <iostream>
#include <typeinfo>
class Person
{
public:
virtual void func()
{
std::cout << typeid(*this).name() << std::endl;
}
};
const char* ClassMangledName(void* address)
{
uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);
uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);
uintptr_t* rttiObject = reinterpret_cast<uintptr_t*>(*(vftablePtr - 1));
std::type_info* ti = reinterpret_cast<std::type_info*>(*(rttiObject + 3));
const char* className = ti->name();
return className;
}
int main()
{
Person p;
std::cout << ClassMangledName(&p) << std::endl;
std::cout << typeid(p).name() << std::endl;
}
运行结果:
class Person
class Person
Windows x64:
#include <iostream>
#include <ehdata.h>
#include <rttidata.h>
class Person
{
public:
virtual void func()
{
std::cout << typeid(*this).name() << std::endl;
}
};
const char* ClassMangledName(void* address)
{
uintptr_t* objPtr = reinterpret_cast<uintptr_t*>(address);
uintptr_t* vftablePtr = reinterpret_cast<uintptr_t*>(*objPtr);
_RTTICompleteObjectLocator* rttiLocator = reinterpret_cast<_RTTICompleteObjectLocator*>(*(vftablePtr - 1));
uintptr_t imageBase = reinterpret_cast<uintptr_t>(rttiLocator) - rttiLocator->pSelf;
TypeDescriptor* typeDescriptor = reinterpret_cast<TypeDescriptor*>(imageBase + rttiLocator->pTypeDescriptor);
const char* classMangledName = typeDescriptor->name;
return classMangledName;
}
int main()
{
Person p;
std::cout << ClassMangledName(&p) << std::endl;
std::cout << typeid(p).raw_name() << std::endl;
}
运行结果:
.?AVPerson@@
.?AVPerson@@
打印的结果是raw name,也就是未修饰的名字。