您的位置:首页 > 其它

MFC六大机制之四:运行时类信息机制(RTTI)

2015-07-03 22:14 302 查看
首先得说明究竟什么是运行时类信息: 程序在运行时,得到对象的类信息以及所属类的继承层次关系。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函数拿到本类的一个静态变量,该变量中保存这本类的信息,和父类的父类的运行时类信息变量的地址,形成一条类的信息链,通过遍历该链表查找类的信息。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: