MFC六大关键技术之仿真学习笔记(三)
来源:互联网 发布:手机淘宝店怎么开不了 编辑:程序博客网 时间:2024/05/16 18:11
如果你感觉前面两节一帆风顺的话,或许从第三节开始,你会感觉理解有一点点困难,或许读完整节,你只能MFC说有这么一个东西,但是并不明白这样设计的好处或如何去使用,别急,让我们慢慢来学习它。
*RTTI(运行时类型识别)
初看RTTI(Runtime Type Identification),我并不是很明白这个玩意的作用,书中有这样的一种比方:当你看到一种颜色,想知道它的RGB值,不查表可以吗?当有你有一种商品,想知道它的型号不差目录行吗?算是明白了,这不仅是一个类类型判断问题,也涉及到如何保存这些类信息的问题,即引入一个“类别型录”的链表,这里链表元素以CRuntimeClass来描述。
struct CRuntimeClass{//AttributesLPCSTR m_lpszClassName; //类名int m_nObjectSize; //对象大小UINT m_wSchema; //模式号,如果不要求支持序列化特性,该域为0xFFFF,否则,不能为0;CObject *(PASCAL *m_pfnCreateObject)(); CRuntimeClass *m_pBaseClass;static CRuntimeClass* pFirstClass; CRuntimeClass* m_pNextClass; };结构如上,我们开始分析:
(1) CObject *(PASCAL *m_pfnCreateObject)(); 定义一个返回CObject* 的函数指针,根据函数指针命名,我们可以知道,它完成的是CreateObject的操作,即一个CRuntimeClass我们就可以产生对应的对象。
(2) CRuntimeClass *m_pBaseClass; 定义一个CRuntimeClass指针指向基类CRuntimeClass,在链表中不仅有前后关系,我们也要实现纵向的继承关系。
(3) static CRuntimeClass *pFirstClass; 定义一个静态成员变量指向链表第一个CRuntimeClass,静态成员变量在产生对象之前进行初始化,并不依赖对象的构造和析构,并且在多个对象中此值唯一。
(4) CRuntimeClass* m_pNextClass; 指针指向链表中下一个元素。
介绍完CRuntimeClass,我们来看看我们最终应该实现的效果:
是的,我们需要一种简便又快捷的方式实现上述链表,那么我们该怎么办?至此,我们需要用宏来实现这些关键步骤,让CRuntimeClass被神不知鬼不觉的塞入我们的类中。当然,别担心,宏只是简单的文本替换。我们来看看具体实现步骤:
(1)MFC定义了一个叫DECLARE_DYNAMIC (也就是动态声明的意思)的宏:
#define DECLARE_DYNAMIC(class_name) \public: \static CRuntimeClass class##class_name; \virtual CRuntimeClass *GetRuntimeClass() const;比如,我们在CWnd中加入宏定义如下:(此处##是讲两个字符串连接到一起)
class CWnd:public CCmdTarget{DECLARE_DYNAMIC(CWnd)}实际上我们加入的是:
class CWnd:public CCmdTarget{public:static CRuntimeClass classCWnd; virtual CRuntimeClass* GetRuntimeClass() const;}我们来分析以上结构:
(1) static CRuntimeClass classCWnd : static变量保存一个对应的CRuntimeClass,这样系统初始化时应该会存在一一对应关系进行初始化,这样我们可以通过CRuntimeClass轻松找到我们需要用的类。
(2) virtual CRuntimeClass* GetRuntimeClass() const :虚函数子类可进行Override,这样的好处是,我们可以轻松找到子类对CRuntimeClass的最新override,不管我们当时是否使用的基类指针(虚函数是根据虚函数表进行读取的)。
这也就是虚函数的魅力所在吧!当然,声明完以后,我们需要去实现它,我们进一步引进了IMPLEMENT_DYNAMIC宏,如下:
#define IMPLEMENT_DYNAMIC(class_name,base_class_name) \_IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,0xFFFF,NULL)IMPLEMENT_DYNAMIC是对_IMPLEMENT_RUNTIMECLASS进行的封装,来看看_IMPLEMENT_RUNTIMECLASS的代码:
#define _IMPLEMENT_RUNTIMECLASS(class_name,base_class_name,wSchema,pfnNew) \static char lpsz##class_name[] = #class_name; \CRuntimeClass class_name::class##class_name = { \lpsz##class_name,sizeof(class_name),wSchema,pfnNew, \RUNTIME_CLASS(base_class_name),NULL }; \static AFX_CLASSINIT _init_##class_name(&class_name::class##class_name); \CRuntimeClass* class_name::GetRuntimeClass() const \{ return &class_name::class##class_name;} \
涉及到RUNTIME_CLASS(class_name)宏:
#define RUNTIME_CLASS(class_name) \(&class_name::class##class_name)
涉及到一个AFX_CLASSINIT结构体(运用结构体的构造函数实现CRuntimeClass链表连接)
struct AFX_CLASSINIT{AFX_CLASSINIT(CRuntimeClass* pNewClass);{ pNewClass->m_pNextClass = CRuntimeClass::pFirstClass; CRuntimeClass::pFirstClass = pNewClass;}};比如我们同样用CWnd来做示范:
IMPLEMENT_DYNAMIC(CWnd, CCmdTarget)我们拆解开看看是啥:
static char lpszCWnd[] = "CWnd";struct CRuntimeClass CWnd::classCWnd = { lpszCWnd, sizeof(szCWnd),wSchema,pfnNew,RUNTIME_CLASS(CCmdTarget),NULL};static AFX_CLASSINIT _init_CWnd(&CWnd::classCWnd);CRuntimeClass* CWnd::GetRuntimeClass() const { return &CWnd::classCWnd;}
以上即实现了DECLARE_DYNAMIC中定义的成员和函数,并将链表增长。
class CObject{public:virtual CRuntimeClass* GetRuntimeClass() const;public:static CRuntimeClass classCObject;};static char lpszCObject[] = "CObject";struct CRuntimeClass CObject::classCObject = { lpszCObject, sizeof(szCObject), 0xFFFF, NULL, NULL, NULL };static AFX_CLASSINIT _init_CObject(&CObject::classCObject);CRuntimeClass* CRuntimeClass::pFirstClass = NULL;CRuntimeClass* CObject::GetRuntimeClass() const{return &CObject::classCObject;}
- 三、MFC 六大关键技术之仿真 (学习笔记)
- MFC六大关键技术之仿真学习笔记(三)
- MFC六大关键技术之仿真学习笔记(一)
- MFC六大关键技术之仿真学习笔记(二)
- MFC六大关键技术之仿真学习笔记(四)
- MFC六大关键技术之仿真学习笔记(六)
- MFC六大关键技术之仿真学习笔记(五)
- MFC六大关键技术之仿真学习笔记(七)
- MFC六大关键技术之仿真学习笔记(八)
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递) .
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建)
- 深入浅出MFC学习笔记:(第三章MFC六大关键技术之仿真:类型识别,动态创建) .
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:命令传递) .
- MFC六大关键技术之仿真(一)
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之MFC程序的初始化过程
- redis系统学习--命令
- The type org.apache.commons.lang.exception.NestableRuntimeException cannot be resolved. 问题解决
- 二 智能闹钟:通知类时间短语
- java多线程并发系列之闭锁(Latch)和栅栏(CyclicBarrier)
- 安装完pip后出现unable to create process using "python.exe"的报错
- MFC六大关键技术之仿真学习笔记(三)
- OpenGL基础知识
- redis系统学习-string命令
- Java集合框架总结(4)——List接口的使用
- Wget
- 从代码分析Android-Universal-Image-Loader的图片加载、显示流程
- 2015年大一下第12周项目2-形状类族的中的纯虚函数
- <C/C++> FILE指针的使用
- redis系统学习-hashes