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();*******************************************************************这个宏的实现相对于之前的更进一步了,定义一个静态的成员函数,这个函数的实现是生成一个类别,而这个类别有CObject*指向,很很明显class_name是CObejct的子类别。并且在实现当中将静态成员函数传递到CRuntimeClass结构体当中,这样的话,CRuntimeClass类别就具有生成class_name类别的所有信息了。#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)
#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
- MFC当中的宏
- MFC当中的后缀名
- MFC 在编程当中遇到的小问题
- MFC当中用到的icon文件图片怎么制作?
- 内核当中的test_bit宏
- 在mfc c++ 以及opencv 编写程序当中,很多常用的类型转换
- 关于MFC当中使用VC(C++)8位BMP提取Y通道平均值的笔记
- MFC一一框架类当中的一些操作(改变标题,设置菜单栏,工具栏)
- MFC对话框当中使用View视图
- VB当中的颜色代码
- java 当中的集合
- JDBC当中的批处理
- javascript当中的setDate()
- Delphi当中的注释
- Java当中的线程
- Java当中的数组
- 数据结构当中的问题
- 复杂的社会当中
- 已经写过的跑跑跑,什么时候能写自己的文章~~
- 简单设计模式-《大话设计模式》笔记
- 【LeetCode】Substring with Concatenation of All Words
- Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database!
- Matlab科研常用命令总结
- MFC当中的宏
- android.mk 详解
- 初步了解欧几里得算法与扩展欧几里得
- TortoiseSVN下载
- codechef GCD2 无穷大数的最大公约数
- Linux私房菜第7章要点回忆
- 第一次用c语言写的五子棋,求大神修改
- Cocos2d-x3.0 Json解析
- umlの交互图