浅谈 typeid

在 vs2010中的typeinfo.h 中 有一个叫 type_info的类  类的接口如下:

class type_info {
public:

    virtual __thiscall ~type_info();
     int __thiscall operator==(_In_ const type_info& _Rhs) const;
     int __thiscall operator!=(_In_ const type_info& _Rhs) const;
     int __thiscall before(_In_ const type_info& _Rhs) const;
private:
    void *_M_data;
    char _M_d_name[1];
    __thiscall type_info(_In_ const type_info& _Rhs);
    type_info& __thiscall operator=(_In_ const type_info& _Rhs);
};


这个类型  有两个变量  _M_data( 4 字节 )     M_d_name (可扩展字节)存储 类型的名字  因为这个类中的析构函数是虚函数  

所以type_info 对象中必须保存一个虚函数表指针( 4 字节 )   所以 这个类型的对象 总共有:4 + 4 +  类型名字的长度 

 type_info  对象 模型:

 

每种类型在内存中 都有其对应的 type_info对象  而且只有一份 。


比如:

class A{};

class B{};

class C{};


A类型  在内存中,有一个type_info 对象

B类型  在内存中,有一个type_info 对象

C类型 在内存中,有一个type_info 对象

A* 类型(指针类型)   在内存中,有一个type_info 对象

A** 类型(双指针类型) 在内存中,有一个type_info 对象


所以:

A  a, a1;      // (a , a1  是同种类型 )

A* pA, pA1;  // (pA, pA1  是同种类型)

B b;


const type_info  typeid(类型或类型对象)

typeid 是编译器,在编译期(不是程序运行期)根据传入的参数(类型或者类型对象【编译器可以根据类型对象的声明,知道对象的类型】)来返回对应类型的 type_info对象

class CType {};

void main()
{

	CType type;
	CType type1;

	void* pCType = (void*)&typeid(CType);  //获得类型CType的type_info的地址
	printf("pCType = %x\n", pCType);

	void* pType  = (void*)&typeid(type);  //获得类型CType的type_info的地址
	printf("pType = %x\n", pType);

	void* pType1 = (void*)&typeid(type1); //获得类型CType的type_info的地址
	printf("pType1 = %x\n", pType1);

	void* pCType_p = (void*)&typeid(CType*);//获得类型CType*的type_info的地址
	printf("pCType_p = %x\n", pCType_p);
	
	void* pCType_pp = (void*)&typeid(CType**);//获得类型CType**的type_info的地址
	printf("pCType_pp = %x\n", pCType_pp);
	
	while (true);
}

运行结果:
可以看到  CType type,type1.     typeid(CType)   typeid(type)  typeid(type1)  返回的 type_info地址是相同的, 说明,一种类型在内存中对应一个type_info对象。

ok,我们看一下对应地址的内存数据:

我们可以看到一些很显眼的数据    ?AVCType@@  (CType类型)    PAVCType@@ (CType* 类型)  PAPAVCType@@ (CType**类型)

拿0x01137034 来分析(根据上面的type_info对象模型图)
98 57 13 01         虚函数指针                 4字节
00 00 00 00        _My_data指针             4字节
2e                       _M_d_name[0]            1字节
3f 41 56 43 54 79 70 65 40 40 00   _M_d_name[1]    类型对应的类型名。
所以:

&type_info+9 == &_M_d_name[1]   

const type_info  typeid(类型或类型对象)

 class type_info

{

public:

......

     int operator==( const type_info& _Rhs) const;

......

}

其中 operator ==  大致如下 

int type_info:: operator == ( const type_info& _Rhs) const

{

return strcmp( &this._M_d_name[1], &_Rhs._M_d_name[1] );

}

我们来调试一下 typeid(CType) == typeid(type)   来推测一下  type_info::operator == 是否正确:

#include <stdio.h>
#include <typeinfo.h>

class CType{};

void main()
{
	CType type;
	
	if(typeid(CType) == typeid(type))
	{
		printf("test\n");
	}
}


 

 if(typeid(CType) == typeid(type))
008F13FE  mov         esi,esp 
008F1400  push        offset CType `RTTI Type Descriptor' (8F7000h)              ;压入参数 typeid(type)
008F1405  mov         ecx,offset CType `RTTI Type Descriptor' (8F7000h)        ;ecx 为this指针    ecx为 typeid(CType)
008F140A  call        dword ptr [__imp_type_info::operator== (8F82C4h)]          ;  调用 operator == 

看一下 __imp_type_info::operator == 的实现

0F31A3B0  mov         edi,edi 
0F31A3B2  push        ebp 
0F31A3B3  mov         ebp,esp 
0F31A3B5  push        ecx 
0F31A3B6  mov         dword ptr [ebp-4],ecx               // this 指针    &type_info 【CType】
0F31A3B9  mov         eax,dword ptr [this] 
0F31A3BC  add         eax,9                                        //  &type_info + 9  【CType】   &_M_d_name[1]
0F31A3BF  push        eax                                          //   入参
0F31A3C0  mov         ecx,dword ptr [rhs] 
0F31A3C3  add         ecx,9                                        //  &type_info + 9 【type】  &_M_d_name[1]
0F31A3C6  push        ecx                                          //   入参
0F31A3C7  call        strcmp (0F29D430h)                 //  调用  strcmp比较字符串
0F31A3CC  add         esp,8 
0F31A3CF  neg         eax 
0F31A3D1  sbb         eax,eax 
0F31A3D3  add         eax,1 
0F31A3D6  mov         esp,ebp 
0F31A3D8  pop         ebp 
0F31A3D9  ret         4 


可以看到最终就是调用  strcmp 比较 type_info的  &_M_d_name[1] 存储的字符串。如果相同,则是同一类型




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值