首先得说明究竟什么是运行时类信息: 程序在运行时,得到对象的类信息以及所属类的继承层次关系。RTTI(Run-Time Type Information,运行时类型信息),下边通过一个例子来说明
1.建一个win32控制台程序。
2.将stdafx.h 添加头文件<afxwin.h>。 3.Project-->Settings菜单项中设置使用MFC库
4.编写代码:
// Dynamic.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//定义支持运行时类信息的类
class CAnimal:public CObject
{
DECLARE_DYNAMIC(CAnimal)
};
IMPLEMENT_DYNAMIC(CAnimal,CObject)
class CDog:public CAnimal
{
DECLARE_DYNAMIC(CDog)
};
IMPLEMENT_DYNAMIC(CDog,CAnimal)
int main(int argc, char* argv[])
{
CDog dog;
if (dog.IsKindOf(RUNTIME_CLASS(CAnimal)))
{
printf("dog is a CAnimal !\n");
}else
{
printf("no no no !\n");
}
CRuntimeClass *pClass=dog.GetRuntimeClass();
printf("类的名称:%s\n",pClass->m_lpszClassName);
printf("类的大小:%d\n",pClass->m_nObjectSize);
return 0;
}
注意:
1 派生自CObject
2 添加动态创建的声明宏和实现宏
DECLARE_DYNCREATE(theClass)
IMPLEMENT_DYNCREATE(theClass,baseClass)
为什么上边的程序可以做判断和输出类信息??? 我们来做个宏代换,结果如下
// Dynamic.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
//定义支持运行时类信息的类
class CAnimal:public CObject
{
DECLARE_DYNAMIC(CAnimal)
};
IMPLEMENT_DYNAMIC(CAnimal,CObject)
class CDog:public CAnimal
{
//DECLARE_DYNAMIC(CDog)
public:
static const AFX_DATA CRuntimeClass classCDog;
virtual CRuntimeClass* GetRuntimeClass() const;
};
//IMPLEMENT_DYNAMIC(CDog,CAnimal)
//IMPLEMENT_RUNTIMECLASS(CDog, CAnimal, 0xFFFF, NULL)
AFX_COMDAT const AFX_DATADEF CRuntimeClass
CDog::classCDog =
{
"CDog",
sizeof(class CDog),
0xFFFF,
NULL,
RUNTIME_CLASS(CAnimal),
NULL
};
CRuntimeClass* CDog::GetRuntimeClass() const
{
//return RUNTIME_CLASS(CDog);
return ((CRuntimeClass*)(&CDog::classCDog));
}
int main(int argc, char* argv[])
{
//判断
CDog dog;
if(dog.IsKindOf(RUNTIME_CLASS(CWnd)))
{
printf("dog is a CWnd!\n");
}
else
{
printf("dog is not a CWnd!\n");
}
//2 获取类的信息
CRuntimeClass *pClass=dog.GetRuntimeClass();
printf("类的名称:%s\n",pClass->m_lpszClassName);
printf("类的大小:%d\n",pClass->m_nObjectSize);
return 0;
}
分析:
1. CDog有一个静态变量和一个虚函数:
classCDog-----类型是CRuntimeClass,的静态成员变量,保存本类信息和父类运行时类信息地址。
GetRuntimeClass------虚函数,作用是返回classCDog的地址
2. CRuntimeClass:用户可以使用该结构获取一个对象及其基类的运行时信息。
struct CRuntimeClass
{
LPCSTR m_lpszClassName;//类的名称
int m_nObjectSize;//类的大小
UINT m_wSchema; //类的版本
CObject* (PASCAL* m_pfnCreateObject)(); //NULL
CRuntimeClass* m_pBaseClass;//父类的运行时类信息变量的地址
...
}
结合我们编写的例子我们很容易看到,现在形成了一个类的信息链表,如下:
CDog::GetRuntimeClass()
|->& classCDog
|->类的名称,大小,版本等信息
|->& classCAnimal
|->CAnimal类的名称、大小、版本等信息
|->& classCObject
|->CObject类的名称、大小版本等
|->NULL
3. IsKindOf函数是怎么实现的??? 加断点,f11进入函数内部,写出伪代码如下:
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
//classCDog的地址
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
pClassThis->IsDerivedFrom(pClass)
{
//classCDog的地址
const CRuntimeClass* pClassThis = this;
while (pClassThis != NULL)
{
//比较
if (pClassThis == pBaseClass)
return TRUE;
//获取父类的变量的地址
pClassThis = pClassThis->m_pBaseClass;
}
return FALSE;
}
}
调用GetRuntimeClass获取&classCDog
调用IsDerivedFrom()函数,在函数中,把&classCDog与参数的&classCWnd比较,如果相等,返回TRUE,表示对象属于该类,如果不相等,获取&classCAnimal,继续循环比较,直到&classCObject的父类的变量地址为空,最后,返回FALSE,表示对象不属于该类。
总结:
其实简单的讲就是同通过GetRuntimeClass函数拿到本类的一个静态变量,该变量中保存这本类的信息,和父类的父类的运行时类信息变量的地址,形成一条类的信息链,通过遍历该链表查找类的信息。