Howto:从C++对象指针得到类名

JAVA程序在运行的时候,有丰富的动态类型信息。而C++则困难的多。C++的运行时类型信息有3种实现方式:语言本身的RTTI、MFC的CObject、QT的moc。下面仅介绍前两种。 一、语言本身的RTTI: 如果是POD类型,如:

class PodPoint{
public:
    int x;
    int y;
};

那么它和C语言中的struct没有什么区别。sizeof(PodPoint)=8。

偏移值 内容
0 x
4 y

别妄想能从它的对象指针中得到什么类型信息。 如果它有虚函数,那么就不一样了

class PodPoint{
public:
    int x;
    int y;
    virtual ~PodPoint(){};
};

在32位程序中,sizeof(PodPoint)=12。这是因为凡是有虚函数,就必须有vtable。所以PodPoint的实际布局就变成了这样:

偏移值 内容
0 指向vtable的指针
4 x
8 y

如果编译的时候打开了RTTI(在vc2005及以上版本默认会打开),那么就很有意思了。在vtable[-1]的位置,是一个特殊的指针,指向RTTI Complete Object Locator,它的第12个字节开始,是一个指针,指向type_info对象。于是我就写了下面这样的代码:

void printMyClassInfo(void *p){
    type_info*** vtable=(type_info***)(*(int*)p);
    type_info** v1=vtable[-1];
    type_info* v=v1[3];
    printf("%s\n",v->name());
}

在有vtable的情况下,这个函数工作的非常好。 二、MFC的RTTI MFC中的大多数对象都从CObject继承而来,例如:

class MyPoint:public CObject{
public:
    int x;
    int y;
    DECLARE_DYNAMIC(MyPoint)
};
IMPLEMENT_DYNAMIC(MyPoint,CObject)

那么我们就可以通过调用CObject的

virtual CRuntimeClass* GetRuntimeClass() const

来得到类名。这个函数一般就在vtable的第一个。 代码如下:

void printClassInfo(void *p){
    int vtable=*(int*)p;
    CRuntimeClass* info;
    __asm{
        mov ecx,p;
        mov eax,vtable;
        call [eax];
        mov info,eax;
    }
    printf("%s",info->m_lpszClassName);
};

假如将上面的IMPLEMENT_DYNAMIC和DECLARE_DYNAMIC去掉,那么输出的结果将是"CObject",而不是"MyPoint",原因很简单。因为子类没有覆盖基类的这个方法嘛。

参考文档:

  1. http://refspecs.linuxbase.org/LSB_4.1.0/LSB-CXX-generic/LSB-CXX-generic/cxxclasses.html
  2. http://www.openrce.org/articles/full_view/23

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥