第一、MFC类图。MFC为编程人员提供了几大用来构建一个Windows程序的类,在通过VC++创建项目时,IDE会给程序员自动添加这些类,当然有些的类是超类,不会IDE不会创建这些类,但是总体的继承结构会保持下来。用MFC编写Windows程序必不可少的类以及类继承结构图如下:
CObject类是所有MFC的父类,CCmdTarget类是消息循环最终的流向场所,所有的消息遍历循环查找操作全部都是在这个类中进行的,也就是说这个决定着消息的流向。而CWinThread类是主线程的管理类,同时也可以创建其他线程,所有MFC的线程都是基于CWinThread类的,其子类CWinApp是管理应用程序的类,里面包含了所有跟你程序相关的数据。CWind类是窗口界面显示管理的类,它分为三个子类,其中CView类是用来显示文档,数据的类,CFrameWnd类是CView类外面的边框,MFC将窗体分为了这两个部分,CDialog类则是对话框类,在本聊天程序中主要用到的就是CDialog对话框类来作为显示界面。CDocument类主要是用来保存程序数据的,每个Document对应一种数据格式。
第二、RTTI(Run-Time Type Identification)运行时类型识别。有了上面的类图继承结构后,我们就需要在写代码的时候将这些类的关系建立起来,就像上图一样,我们就需要用到RTTI了,RTTI主要的核心思想,在我们每创建一个自己的类时,将该类添加到一个动态的链表中,在MFC中叫做CRuntimeClass,在CRuntimeClass中保存了一个动态链表,将所有用户建立的类都按上图创建了一个类图关系。而MFC通过DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC两个宏帮我们做完成了这个链表的创建、添加、等操作,DECLARE_DYNAMIC是在类的声明时添加,IMPLEMENT_DYNAMIC是在类实现的时候添加。
第三、Dynamic Creation(动态创建)。有了运行时类型识别,我们就可以动态创建了,因为每次需要创建新类时,我们就可以在CRuntimeClass中遍历链表,如果找到这种类型的类我们就直接创建,如果没有,我们就先将这个类添加到这个链表中,然后在创建这个类的实例对象。但是这个步骤MFC也帮我们做好了,是通过DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE两个宏完成的。通过以上三个技术,每次当我们自己添加新类的时候,MFC就为我们自动的构建了一张系统类图结构,而且每个类之间是互通的可以相互关联的,但是要完成消息的传递路由还需要下面三个技术。
第四、Persistence(永久保存)机制。由于本聊天程序没有要求将聊天记录生成文件保存,所以这个技术在本聊天程序中用不到。但是在MFC中通过这个机制,将用户输入的数据全部都保存下来,同时也可以打开同类型的文件。而这个技术的核心就是Serialize()这个函数,每个CDocument类或其子类都会复写这个方法,以实现文件的保存。MFC通过DECLARE_SERIAL/IMPLEMENT_SERIAL两个宏来替我们完成Serialize()的框架。
第五、Message Mapping(消息映射)。MFC程序中系统消息能够传到每个类各自负责的函数、方法中,每个类都能处理属于他独特的消息事件,主要就是通过消息映射来完成的,其实消息映射有点像第二个技术动态创建类的结构关系,而这里只是针对程序中每个类中的消息进行一个动态链表的建立。因为消息包含一个消息指针和一个消息实体,消息实体里面存放着改消息属于哪个类,它对应的执行函数是哪个等参数,而消息指针则指向该类的父类的消息,以便系统在本类找不到处理消息的函数的时候可以去父类中查找,通过这样构建出一个消息结构图,可以完成程序消息间的流向图实现消息查找执行。MFC通过DECLARE_MESSAGE_MAP()/BEGIN_MESSAGE_MAP() ON_COMMAND()…END_MESSAGER_MAP()几个宏完成的,其中ON_COMMAND()就是将为本类添加消息处理方法的一个映射表,可以有多个出现,每一个都代表着本来可以处理的一种对应的消息。
第六、Command Routing(命令传递)。有了上面第五点的消息映射,消息传递的过程就很简单了,其中MFC的消息有两类,一类是普通消息,一类是系统消息,普通消息都是从派生类将消息传递到父类中,而系统消息就有点复杂了,这里简单的说一些他的过程。系统消息先由CFrameWnd类接受消息,并且传递给其父类CWind类,这里CWind类中的消息处理只是做一个消息传递的工作,而CWind类则交给CView类处理,如果没有处理函数这要CView类的父类CWind处理,同样这里CWind类中的消息处理只是做一个消息传递的工作,如果还没有找到,则系统会要求CDocument类处理,如果没有匹配的则又会回到CWind类中,然后在CWind类遍历自己的消息映射表,如果没有对应的处理则表消息处理权流回到CWinApp类中,如果还没有找到则会退回到CWind类中执行DefWindowProc()函数。因此整个消息传递过程就结束了。