MFC当中的宏

来源:互联网 发布:q版泡泡堂mac 编辑:程序博客网 时间:2024/05/20 02:28

要分析MFC的实现首先要从MFC当中众多的宏开始讨论。首先看一个上次讲到的宏:

#define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))
这个宏的实现很简单,就是返回一个类当中的一个成员变量的地址,这个成员变量要么是静态成员变量,要么是虚拟函数。因为用命名空间符提取只能用于这两种情况。先留下疑问,看看CRuntimeClass的定义。
   struct CRuntimeClass   {   LPCSTR m_lpszClassName;             //存放类的名称   int m_nObjectSize;                  //类的尺寸大小   UINT m_wSchema;                     // 一个标志符号   CObject* (PASCAL* m_pfnCreateObject)(); //如果这个函数为空,则表明类是一个虚拟类,不能有实例   CRuntimeClass* m_pBaseClass;            //基类的CRuntimeClass   CObject* CreateObject();                //创建   BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;//判断两个类别是否具有继承关系   void Store(CArchive& ar) const;                           //用于存放类别信息   static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);//用于加载类别信息   CRuntimeClass* m_pNextClass;       // 将整个CRuntimeClass类别链成一个链表   };***************************************************************/*下面这个宏展开之后,定义了一个与类名息息相关的静态CRuntimeClass成员变量,另外定义了一个虚拟函数用于获取相应类的CRuntimeClass*/   #define DECLARE_DYNAMIC(class_name) \   public: \   static const AFX_DATA CRuntimeClass class##class_name; \virtual CRuntimeClass* GetRuntimeClass() const; \*********************************************************************/*用于对CRuntimeClass结构体进行填充,由于后面的成员函数并不是指针类型的,所以不需要填充。同时实现上面的GetRuntimeClass函数*/

#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, pfnNew) \

AFX_COMDAT const AFX_DATADEF CRuntimeClass class_name::class##class_name = { \

#class_name, sizeof(class class_name), wSchema, pfnNew, \

RUNTIME_CLASS(base_class_name), NULL }; \

CRuntimeClass* class_name::GetRuntimeClass() const \

{ return RUNTIME_CLASS(class_name); } \

***************************************************************

#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \

IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)

通过上面的分析,不难看出,每个类都有一个类似于管家的结构体,这个结构体包含自身的信息,并且这个信息在整个程序当中是唯一的,同时这个结构体包含基类的的RuntimeClass的指针。

   #define DECLARE_DYNCREATE(class_name) \   DECLARE_DYNAMIC(class_name) \   static CObject* PASCAL CreateObject();*******************************************************************

#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \

CObject* PASCAL class_name::CreateObject() \

{ return new class_name; } \

IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \

class_name::CreateObject)

这个宏的实现相对于之前的更进一步了,定义一个静态的成员函数,这个函数的实现是生成一个类别,而这个类别有CObject*指向,很很明显class_name是CObejct的子类别。并且在实现当中将静态成员函数传递到CRuntimeClass结构体当中,这样的话,CRuntimeClass类别就具有生成class_name类别的所有信息了。

   #define DECLARE_SERIAL(class_name) \   _DECLARE_DYNCREATE(class_name) \   AFX_API friend CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb);******************************************************************************************
   #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \   CObject* PASCAL class_name::CreateObject() \   { return new class_name; } \   _IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \   class_name::CreateObject) \   AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \   CArchive& AFXAPI operator>>(CArchive& ar, class_name* &pOb) \

{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \

return ar; } \

这个宏的实现实际上是用于在整个类的文档化,既将整个类的信息保存到文件当中,然后从文件中读出来,并进行相应的初始化。

上面的CRuntimeClass将所有的从CObject类继承来的类别连接一个链表,这样就可以在父类和子类之间传递消息,直到消息被其中某一个类处理或者所有的类都不处理,那么就到了默认的处理函数,也就是DefWindowProc。

BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const{ const CRuntimeClass* pClassThis = this;   while (pClassThis != NULL)   {   if (pClassThis == pBaseClass)   return TRUE;   pClassThis = pClassThis->m_pBaseClass;   }   return FALSE;}CObject* CRuntimeClass::CreateObject(){   if (m_pfnCreateObject == NULL)   {   return NULL;   }   CObject* pObject = NULL;   TRY   {   pObject = (*m_pfnCreateObject)();   }   END_TRY   return pObject;}
从上面的实实现可以看出,由于整个程序当中一个类对应一个CRuntimeClass,所以这里的数据是唯一的,如果某一个类是另外一个类的基类,那么通过回溯整个CRuntimeClass类总会有一个指针域pBaseClass相等。而下面的CreateObject则给了一个用户处理的机会。

0 0