MFC的类层次(
MFC(微软基础类)也是一种应用程序框架,定义了应用程序的一般处理流程,用于对Windows API实现基于面向对象技术的封装,隐藏在Windows下使用C++编程的大量内部细节。在开发应用程序的过程中,编程人员可以通过对类库中已有类的继承,生成功能更加强大的类库以供自己所用。
在MFC中类的层次结构(即继承关系)如图5-3所示。
从图中可知,在MFC中大多数的类都派生于CObject类,它的主要作用是为子类提供一些基本的功能,这些派生类构成了MFC应用程序的基本框架,它们各自的功能描述如表5-1所示。
派生类 |
功能描述 |
CCmdTarget |
用于处理用户请求 |
CWinThread |
代表应用程序内部的执行线程 |
CWinApp |
应用程序的核心 |
CWnd |
为所有的窗口类提供基本的功能,处理常见的系统消息 |
CView |
用于显示数据并与文档对象进行交互 |
CFrameWnd |
应用程序的主框架 |
CDocument |
包含应用程序的数据集 |
下面将对上述表中各个类的功能进行具体的讲解。
1)CCmdTarget类
CCmdTarget类是MFC的消息映射基础类,MFC为该类设计了许多的成员变量及函数以解决消息映射的问题。派生于CCmdTarget的类可用于处理当用户选择菜单或单击按钮等操作时所产生的Command消息。
在实际的开发过程中,我们通常很少直接从CCmdTarget中派生类。当想要生成一个处理按键消息的类时,只需从继承于CCmdTarget类的框架子类CView、CWinApp、CDocument、CWnd和CFrameWnd中选择一个来充当父类即可。
2)CWinThread类
CWinThread类是MFC中用于封装线程的类,它的成员函数可以使MFC应用程序创建和管理包括UI及工作者在内的线程。每个MFC应用程序都至少应该使用一个从CWinThread派生的类,应用程序类CWinApp就是一个代表。
3)CWinApp类
CWinApp类通常代表应用程序自己,它封装了应用程序的初始化、运行及终止的过程。基于框架的应用程序必须有且仅有一个派生于CWinApp的类的对象,并在完成窗口的创建工作之前执行对该对象的构造。
应用程序类的对象需要完成以下工作。
初始化应用程序。
建立文档模板结构。
循环检索消息队列中的消息并将这些消息发送到指定的地方。
执行应用程序退出时的清理工作。
4)CDocument类
CDocument类是在使用文档/视图结构的应用程序中文档对象的基类,它为应用程序的文档对象提供了基本的功能,包括新建、串行化数据等。
5)CWnd类
CWnd类是所有MFC 窗口的基类,它封装了窗口的基本操作,包括窗口的创建、销毁、设置窗口风格等,以及窗口对大部分消息的默认响应。开发人员可以直接从CWnd派生其他类,但通常情况下我们并不这么做,而是通过继承CWnd的派生类生成新类。
6)CFrameWnd类
CFrameWnd类往往用于创建应用程序的主窗口,并定义了大量管理视图和文档对象的成员函数及变量。在编写文档/视图结构的应用程序时,视图对象等将作为CFrameWnd的子窗口实现对客户区的共享,并被CFrameWnd有序排列。
7)CView类
CView类是在使用文档/视图结构的应用程序中视图对象的基类,它是用户的主要操作界面。在应用程序中,一个视图对象通常只对应一个文档对象,但一个文档对象却可以关联多个视图对象,并且每个视图对象都以不同的形式来显示文档中的数据。
在上述CObject类的派生类中,CWinApp类、CDocument类、 CCmdTarget类及CWinThread类构成了应用程序的结构类,代表了应用程序的基本结构元素。换句话说,当一个应用程序开始运行时,这些类将最先实现初始化。
在类的层次结构中,应用程序类CWinApp是一个基于MFC应用程序的最外层对象容器,它不仅拥有诸如实例句柄等需要被传送到WinMain()函数中去的参数,还包含了应用程序的主框架窗口,当主框架窗口被关闭时,应用程序也就跟着结束了。因此,开发人员必须为程序创建一个全局的应用程序对象。
静态链接库与动态链接库的区别:
(1)静态链接库与动态链接库 都是共享代码的方式 。静态链接库把最后的指令 都包含 在最终生成的EXE文件中了;动态链接库不必被包含在最终EXE文件中,EXE文件 执行时可以“动态”地引用和卸载 这个与EXE独立的DLL文件。
(2) 静态链接库中 不能再包含其他的动态链接库或者静态库 ,而在动态链接库中还可以再包含其他的动态或静态链接库。
DLL分类:
1。Non-MFC DLL(非MFC动态库):不采用MFC类库结构,其导出函数为标准的C接口,能被非MFC或MFC编写的应用程序所调用;
2。MFC Regular DLL(MFC规则DLL):非MFC动态库MFC规则DLL 包含一个继承自CWinApp的类,但其无消息循环;
3。MFC Extension DLL(MFC扩展DLL):采用MFC的动态链接版本创建,它 只能被用MFC类库所编写的应用程序所调用。
1 使用者在Viewl做动作(View扮演使用者接口的第一线)。
2 Viewl调用GetDocument,取得Document指针,更改资料内容。
3 Viewl调用Document的UpdateAllViews。
4 View2和View3的OnUpdate一一被调用起来,这是更新画面的时机。
CView::OnUpdate被调用,代表着View被告知:“嘿,Document的内容己经改变了,请你准备修改你的显示画面”。如果你想节省力气,利用Invalidate(TRUE)把窗口整个设为重绘区(无效区)并产生WM_PAINT,再让CView::OnDraw去伤脑筋算了。但是全部重绘的效率低落,程序看起来很笨拙。
一:什么是.NET?它包括什么?
.Net是为简化在第三代因特网的高分布式环境下的应用程序开发,基于开放互联网标准和协议之上,实现异质语言和平台高度交互性,而构建的新一代计算和通信平台。
.Net主要包括公共语言运行时(CommonLanguage Runtime)和.Net构架类库。
二: .NET的主要优点有哪些?
.Net的主要优点有跨语言,跨平台,安全,以及对开放互联网标准和协议的支持.
.Net支持多种语言的互操作,即在一种语言下开发的组件,可在另一组件下通过面向对象的继承而得
以重用,目前.Net支持的语言达二十多种。
.Net通过将各语言先编译成中间语言(IL),然后再执行时用即时编译器(Just In Time)将之编译成本
地平台代码来实现异构平台下对象的互操作,目前.Net支持的平台有Windows,Linux和Unix的支持正
在开发中。
连接远程设备,交互远程应用的编程界面.
11).关于MFC的消息机制。
MFC使用一种消息映射机制来处理消息,在应用程序框架中的表现就是一个消息与消息处理函数一一对应的消息映射表,以及消息处理函数的声明和实现等代码。当窗口接收到消息时,会到消息映射表中查找该消息对应的消息处理函数,然后由消息处理函数进行相应的处理。SDK编程时需要在窗口过程中一一判断消息值进行相应的处理,相比之下MFC的消息映射机制要方便好用的多。
12).进程/线程间的通信
线程间通信:由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。
进程间的通信则不同,它的数据空间的独立性决定了它的通信相对比较复杂,需要通过操作系统。以前进程间的通信只能是单机版的,现在操作系统都继承了基于套接字(socket)的进程间的通信机制。这样进程间的通信就不局限于单台计算机了,实现了网络通信。
进程的通信机制主要有:管道、有名管道、消息队列、信号量、共享空间、信号、套接字。
管道:它传递数据是单向性的,只能从一方流向另一方,也就是一种半双工的通信方式;只用于有亲缘关系的进程间的通信,亲缘关系也就是父子进程或兄弟进程;没有名字并且大小受限,传输的是无格式的流,所以两进程通信时必须约定好数据通信的格式。管道它就像一个特殊的文件,但这个文件之存在于内存中,在创建管道时,系统为管道分配了一个页面作为数据缓冲区,进程对这个数据缓冲区进行读写,以此来完成通信。其中一个进程只能读一个只能写,所以叫半双工通信,为什么一个只能读一个只能写呢?因为写进程是在缓冲区的末尾写入,读进程是在缓冲区的头部读取,他们各自 的数据结构不同,所以功能不同。
有名管道:看见这个名字就能知道个大概了,它于管道的不同的是它有名字了。这就不同与管道只能在具有亲缘关系的进程间通信了。它提供了一个路径名与之关联,有了自己的传输格式。有名管道和管道的不同之处还有一点是,有名管道是个设备文件,存储在文件系统中,没有亲缘关系的进程也可以访问,但是它要按照先进先出的原则读取数据。同样也是单双工的。
消息队列:是存放在内核中的消息链表,每个消息队列由消息队列标识符标识,于管道不同的是,消息队列存放在内核中,只有在内核重启时才能删除一个消息队列,内核重启也就是系统重启,同样消息队列的大小也是受限制的。
信号量:也可以说是一个计数器,常用来处理进程或线程同步的问题,特别是对临界资源的访问同步问题。临界资源:为某一时刻只能由一个进程或线程操作的资源,当信号量的值大于或等于0时,表示可以供并发进程访问的临界资源数,当小于0时,表示正在等待使用临界资源的进程数。更重要的是,信号量的值仅能由PV操作来改变。
共享内存:就是分配一块能被其他进程访问的内存。共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。首先说下在使用共享内存区前,必须通过系统函数将其附加到进程的地址空间或说为映射到进程空间。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到 进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互 斥锁和信号量都可以。采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就 解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存 中的内容往往是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。
信号:信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源。信号分为可靠信号和不可靠信号,实时信号和非实时信号。进程有三种方式响应信号1.忽略信号2.捕捉信号3.执行缺省操作。
套接字:套接字是通信端点的抽象,就是这个通信端点的逻辑代表。
13.)线程同步与互斥在引入多线程后,由于线程执行的异步性,会给系统造成混乱,特别是在急用临界资源时,如多个线程急用同一台打印机,会使打印结果交织在一起,难于区分。当多个线程急用共享变量,表格,链表时,可能会导致数据处理出错,因此线程同步的主要任务是使并发执行的各线程之间能够有效的共享资源和相互合作,从而使程序的执行具有可再现性。
当线程并发执行时,由于资源共享和线程协作,使用线程之间会存在以下两种制约关系。
(1)间接相互制约。一个系统中的多个线程必然要共享某种系统资源,如共享CPU,共享I/O设备,所谓间接相互制约即源于这种资源共享,打印机就是最好的例子,线程A在使用打印机时,其它线程都要等待。
(2)直接相互制约。这种制约主要是因为线程之间的合作,如有线程A将计算结果提供给线程B作进一步处理,那么线程B在线程A将数据送达之前都将处于阻塞状态。
间接相互制约可以称为互斥,直接相互制约可以称为同步,对于互斥可以这样理解,线程A和线程B互斥访问某个资源则它们之间就会产个顺序问题——要么线程A等待线程B操作完毕,要么线程B等待线程操作完毕,这其实就是线程的同步了。因此同步包括互斥,互斥其实是一种特殊的同步。