对象与对象的类型信息----获取对象的RTTI信息
梦在天涯 在上篇文章里问可不可以研究下对象与对象的类型信息怎么联系起来的,就是当调用dynamic_cast的时候为什么能够正确的识别对象的类型
RTTI(Run Time Type Identification)运行时类型识别是有编译器在编译器生成的特殊类型信息,包括对象继承关系,对象本身的描述,RTTI是为多态而生成的信息,所以只有具有虚函数的对象在会生成
那RTTI在哪里呢?
MSVC编译器在vftable前设置了一个指针,指向叫做“Complete Object Locator”(完整对象定位器)的结构。这样称呼是因为它允许编译器从特定的vftable指针(因为一个类可能有若干vftable)找到完整对象的位置。COL就像如下定义:
请看如下代码:
1#include "iostream"
2#include "string"
3
4
5using namespace std;
6class Aclass
7{
8public:
9 int a;
10 virtual void setA(int tmp)
11 {
12 a=tmp;
13 cout<<a<<endl;
14 }
15};
16class Bclass:public Aclass
17{
18public:
19 virtual void setA(int tmp)
20 {
21 a=tmp+10;
22 cout<<a<<endl;
23 }
24public:
25 void print()
26 {
27 cout<<a<<endl;
28 }
29};
30class Cclass:public Bclass
31{
32};
33typedef unsigned long DWORD;
34struct TypeDescriptor
35{
36 DWORD ptrToVTable;
37 DWORD spare;
38 char name[8];
39};
40struct PMD
41{
42
43 int mdisp; //member displacement
44
45 int pdisp; //vbtable displacement
46
47 int vdisp; //displacement inside vbtable
48
49};
50struct RTTIBaseClassDescriptor
51
52{
53
54 struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class
55
56 DWORD numContainedBases; //number of nested classes following in the Base Class Array
57
58 struct PMD where; //pointer-to-member displacement info
59
60 DWORD attributes; //flags, usually 0
61
62};
63
64struct RTTIClassHierarchyDescriptor
65{
66
67 DWORD signature; //always zero?
68
69 DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
70
71 DWORD numBaseClasses; //number of classes in pBaseClassArray
72
73 struct RTTIBaseClassArray* pBaseClassArray;
74
75};
76
77struct RTTICompleteObjectLocator
78
79{
80
81 DWORD signature; //always zero ?
82
83 DWORD offset; //offset of this vtable in the complete class
84
85 DWORD cdOffset; //constructor displacement offset
86
87 struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the complete class
88
89 struct RTTIClassHierarchyDescriptor* pClassDescriptor; //describes inheritance hierarchy
90
91
92};
93
94
95int _tmain(int argc, _TCHAR* argv[])
96{
97 Aclass* ptra=new Bclass;
98 int ** ptrvf=(int**)(ptra);
99 RTTICompleteObjectLocator str=
100 *((RTTICompleteObjectLocator*)(*((int*)ptrvf[0]-1)));
101 //abstract class name from RTTI
102 string classname(str.pTypeDescriptor->name);
103 classname=classname.substr(4,classname.find("@@")-4);
104 cout<<classname<<endl;
105 system("pause");
106 return 0;
107}
108
2#include "string"
3
4
5using namespace std;
6class Aclass
7{
8public:
9 int a;
10 virtual void setA(int tmp)
11 {
12 a=tmp;
13 cout<<a<<endl;
14 }
15};
16class Bclass:public Aclass
17{
18public:
19 virtual void setA(int tmp)
20 {
21 a=tmp+10;
22 cout<<a<<endl;
23 }
24public:
25 void print()
26 {
27 cout<<a<<endl;
28 }
29};
30class Cclass:public Bclass
31{
32};
33typedef unsigned long DWORD;
34struct TypeDescriptor
35{
36 DWORD ptrToVTable;
37 DWORD spare;
38 char name[8];
39};
40struct PMD
41{
42
43 int mdisp; //member displacement
44
45 int pdisp; //vbtable displacement
46
47 int vdisp; //displacement inside vbtable
48
49};
50struct RTTIBaseClassDescriptor
51
52{
53
54 struct TypeDescriptor* pTypeDescriptor; //type descriptor of the class
55
56 DWORD numContainedBases; //number of nested classes following in the Base Class Array
57
58 struct PMD where; //pointer-to-member displacement info
59
60 DWORD attributes; //flags, usually 0
61
62};
63
64struct RTTIClassHierarchyDescriptor
65{
66
67 DWORD signature; //always zero?
68
69 DWORD attributes; //bit 0 set = multiple inheritance, bit 1 set = virtual inheritance
70
71 DWORD numBaseClasses; //number of classes in pBaseClassArray
72
73 struct RTTIBaseClassArray* pBaseClassArray;
74
75};
76
77struct RTTICompleteObjectLocator
78
79{
80
81 DWORD signature; //always zero ?
82
83 DWORD offset; //offset of this vtable in the complete class
84
85 DWORD cdOffset; //constructor displacement offset
86
87 struct TypeDescriptor* pTypeDescriptor; //TypeDescriptor of the complete class
88
89 struct RTTIClassHierarchyDescriptor* pClassDescriptor; //describes inheritance hierarchy
90
91
92};
93
94
95int _tmain(int argc, _TCHAR* argv[])
96{
97 Aclass* ptra=new Bclass;
98 int ** ptrvf=(int**)(ptra);
99 RTTICompleteObjectLocator str=
100 *((RTTICompleteObjectLocator*)(*((int*)ptrvf[0]-1)));
101 //abstract class name from RTTI
102 string classname(str.pTypeDescriptor->name);
103 classname=classname.substr(4,classname.find("@@")-4);
104 cout<<classname<<endl;
105 system("pause");
106 return 0;
107}
108
输出结果:
在RTTI运行时结构体中包含许多丰富的信息,甚至我们可以利用一个实例的RTTI信息去复原整个类继承图谱
而对于dynamic_cast也是利用这个信息来准确的识别实例所对应的类型,不过如果对于没有多态的实例,dynamic_cast所做的也只是和编译器类型转换一样的事情,仅仅是通过类型和继承关系进行转换,还是看例子吧:
1class mother
2{
3 int a;
4 int b;
5};
6class father
7{
8 double c;
9};
10class son:public mother,public father
11{
12 char a;
13 short c;
14};
15
16int _tmain(int argc, _TCHAR* argv[])
17{
18 mother* m=new son();
19 father* f=dynamic_cast<father*>(m);
20 system("pause");
21 return 0;
22}
2{
3 int a;
4 int b;
5};
6class father
7{
8 double c;
9};
10class son:public mother,public father
11{
12 char a;
13 short c;
14};
15
16int _tmain(int argc, _TCHAR* argv[])
17{
18 mother* m=new son();
19 father* f=dynamic_cast<father*>(m);
20 system("pause");
21 return 0;
22}
运行会得到以下错误:
error C2683: “dynamic_cast”:“mother”不是多态类型
修改如下
class mother
{
int a;
int b;
virtual void fun()
{
}
};
一切正常
就说这么多吧,欢迎多交流