📄 chap2_4.htm
字号:
<p><span style="font-size: 9pt">class CObject</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">// Object model (types, destruction, allocation)</span></p>
<p><span style="font-size: 9pt">virtual CRuntimeClass* GetRuntimeClass() const;</span></p>
<p><span style="font-size: 9pt">virtual ~CObject(); // virtual destructors are necessary</span></p>
<p><span style="font-size: 9pt">// Diagnostic allocations</span></p>
<p><span style="font-size: 9pt">void* PASCAL operator new(size_t nSize);</span></p>
<p><span style="font-size: 9pt">void* PASCAL operator new(size_t, void* p);</span></p>
<p><span style="font-size: 9pt">void PASCAL operator delete(void* p);</span></p>
<p><span style="font-size: 9pt">#if defined(_DEBUG) && !defined(_AFX_NO_DEBUG_CRT)</span></p>
<p><span style="font-size: 9pt">// for file name/line number tracking using DEBUG_NEW</span></p>
<p><span style="font-size: 9pt">void* PASCAL operator new(size_t nSize, LPCSTR
lpszFileName, int nLine);</span></p>
<p><span style="font-size: 9pt">#endif</span></p>
<p><span style="font-size: 9pt">// Disable the copy constructor and assignment by default
so you will get</span></p>
<p><span style="font-size: 9pt">// compiler errors instead of unexpected behaviour if you
pass objects</span></p>
<p><span style="font-size: 9pt">// by value or assign objects.</span></p>
<p><span style="font-size: 9pt">protected:</span></p>
<p><span style="font-size: 9pt">CObject();</span></p>
<p><span style="font-size: 9pt">private:</span></p>
<p><span style="font-size: 9pt">CObject(const CObject& objectSrc); // no
implementation</span></p>
<p><span style="font-size: 9pt">void operator=(const CObject& objectSrc); // no
implementation</span></p>
<p><span style="font-size: 9pt">// Attributes</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">BOOL IsSerializable() const;</span></p>
<p><span style="font-size: 9pt">BOOL IsKindOf(const CRuntimeClass* pClass) const;</span></p>
<p><span style="font-size: 9pt">// Overridables</span></p>
<p><span style="font-size: 9pt">virtual void Serialize(CArchive& ar);</span></p>
<p><span style="font-size: 9pt">// Diagnostic Support</span></p>
<p><span style="font-size: 9pt">virtual void AssertValid() const;</span></p>
<p><span style="font-size: 9pt">virtual void Dump(CDumpContext& dc) const;</span></p>
<p><span style="font-size: 9pt">// Implementation</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">static const AFX_DATA CRuntimeClass classCObject;</span></p>
<p><span style="font-size: 9pt">#ifdef _AFXDLL</span></p>
<p><span style="font-size: 9pt">static CRuntimeClass* PASCAL _GetBaseClass();</span></p>
<p><span style="font-size: 9pt">#endif</span></p>
<p><span style="font-size: 9pt">};</span></p>
<p><span style="font-size: 9pt">CObject类为派生类提供了下述服务:</span></p>
<blockquote>
<p><span style="font-size: 9pt">对象诊断</span></p>
<p><span style="font-size: 9pt">MFC提供了许多诊断特性,它可以:</span></p>
<p><span style="font-size: 9pt">输出对象内部信息:CDumpContext类与CObject的成员函数Dump配合,用于在调试程序时输出对象内部数据。</span></p>
<p><span style="font-size: 9pt">对象有效性检查:重载基类的AssertValid成员函数,可以为派生类的对象提供有效性检查。</span></p>
<p><span style="font-size: 9pt">运行时访问类的信息:</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">MFC提供了一个非常有用的特性,它可以进行运行时的类型检查。如果从CObject派生出一个类,并使用了以下三个宏(IMPLEMENT_DYNAMIC,IMPLEMENT_
DYNCREATE或IMPLEMENT_SERIAL)之一,就可以:</span></p>
<p><span style="font-size: 9pt">运行时访问类名</span></p>
<p><span style="font-size: 9pt">安全可靠的把通用的CObject指针转化为派生类的指针</span></p>
<p><span style="font-size: 9pt">比如,我们定义一个主窗口类</span></p>
<p><span style="font-size: 9pt">CMyFrame:public CFrameWnd</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">......</span></p>
<p><span style="font-size: 9pt">}</span></p>
<p><span style="font-size: 9pt">然后我们使用这个类:</span></p>
<p><span style="font-size: 9pt">CMyFrame *pFrame=(CMyFrame*)AfxGetMainWnd();</span></p>
<p><span style="font-size: 9pt">pFrame->DoSomeOperation();</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">AfxGetMainWnd是一个全局函数,返回指向应用程序的主窗口的指针,类型为CWnd*,因此我们必须对它进行强制类型转换,但我们如何知道是否转换成功了呢?我们可以使用CObject的IsKindOf()成员函数检查pFrame的类型,用法如下:</span></p>
<p><span style="font-size: 9pt">ASSERT(pFrame->IsKindOf(RUN_TIMECLASS(CMyFrame)));</span></p>
<p><span style="font-size: 9pt">将上一语句插入到pFrame-> DoSomeOperation()之前,就可以在运行时作类型检查,当类型检查失败时,引发一个断言(ASSERT),中断程序执行。</span></p>
<p><span style="font-size: 9pt">对象持续性</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">通过与非CObject派生的档案类CArchive相结合,提供将多个不同对象以二进制形式保存到磁盘文件(Serilization)中以及根据磁盘文件中的对象状态数据在内存中重建对象(Deserilization
)的功能。</span></p>
</blockquote>
<p><span style="font-size: 9pt">然而,MFC不仅仅是一个类库,它还提供了一层建立在Windows
API的C++封装上的附加应用程序框架。该框架提供了Windows程序需要的多数公共用户界面。</span></p>
<p><span style="font-size: 9pt">所谓应用程序框架指的是为了生成一般的应用所必须的各种软组件的集成。应用框架是类库的一种超集。一般的类库只是一种可以用来嵌入任何程序中的、提供某些特定功能(如图象处理、串行通信)的孤立的类的集合,但应用框架却定义了应用程序的结构,它的类既相互独立,又相互依赖,形成一个统一的整体,可以用来构造大多数应用程序。中国用户熟悉的Borland
C++的DOS下的Turbo Vision和Windows下OWL(Object Windows Language)都是应用框架的例子。</span></p>
<p><span style="font-size: 9pt">下面我们举个具体的例子来说明MFC所提供的应用程序框架,程序如清单2.2。</span><b></p>
<p><span style="font-size: 9pt">清单2.2应用程序框架示例</span></b></p>
<p><span style="font-size: 9pt">#include<afxwin.h></span></p>
<p><span style="font-size: 9pt">//derived an application class</span></p>
<p><span style="font-size: 9pt">class CMinMFCApp:public CWinApp</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">BOOL InitInstance();</span></p>
<p><span style="font-size: 9pt">};</span></p>
<p><span style="font-size: 9pt">//Derive the main window class</span></p>
<p><span style="font-size: 9pt">class CMainWindow:public CFrameWnd</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">CMainWindow();</span></p>
<p><span style="font-size: 9pt">DECLARE_MESSAGE_MAP()</span></p>
<p><span style="font-size: 9pt">};</span></p>
<p><span style="font-size: 9pt">BEGIN_MESSAGE_MAP(CMainWindow,CFrameWnd)</span></p>
<p><span style="font-size: 9pt">END_MESSAGE_MAP()</span></p>
<p><span style="font-size: 9pt">/*CMinMFCApp Member Functions*/</span></p>
<p><span style="font-size: 9pt">BOOL CMinMFCApp::InitInstance()</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">m_pMainWnd=new CMainWindow();</span></p>
<p><span style="font-size: 9pt">m_pMainWnd->ShowWindow(m_nCmdShow);</span></p>
<p> </p>
<p><span style="font-size: 9pt">m_pMainWnd->UpdateWindow(); </span></p>
<p><span style="font-size: 9pt">return TRUE;</span></p>
<p><span style="font-size: 9pt">}</span></p>
<p><span style="font-size: 9pt">/*CMainWindow member functions*/</span></p>
<p><span style="font-size: 9pt">CMainWindow::CMainWindow()//constructor</span></p>
<p><span style="font-size: 9pt">{</span></p>
<p><span style="font-size: 9pt">Create(NULL,</span></p>
<p><span style="font-size: 9pt">"Min MFC Application",</span></p>
<p><span style="font-size: 9pt">WS_OVERLAPPEDWINDOW,</span></p>
<p><span style="font-size: 9pt">rectDefault,</span></p>
<p><span style="font-size: 9pt">NULL,</span></p>
<p><span style="font-size: 9pt">NULL);</span></p>
<p><span style="font-size: 9pt">}</span></p>
<p><span style="font-size: 9pt">/*an instance of type CMinMFCApp*/</span></p>
<p><span style="font-size: 9pt">CMinMFCApp ThisApp;</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">清单2.2程序段定义了一个最小的MFC应用程序所需的框架程序。其中声明了CMinMFCApp类,它是从应用程序类CWinApp中派生下来的;和窗口CMainWindow类,它是从框架窗口CFrameWnd类派生出来。我们还用CMinMFCApp定义了一个全局对象ThisApp。读者也许会问,为什么没有WinMain函数?因为MFC已经把它封装起来了。在程序运行时,MFC应用程序首先调用由框架提供的标准的WinMain函数。在WinMain函数中,首先初始化由CMinMFCApp定义的唯一的实例,然后调用CMinMFCApp继承CWinApp的Run成员函数,进入消息循环。退出时调用CWinApp的ExitInstance函数。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">由上面的说明可以看到,应用程序框架不仅提供了构建应用程序所需要的类(CWinApp,CFrameWnd等),还定义了程序的基本执行结构。所有的应用程序都在这个基本结构基础上完成不同的功能。</span></p>
<p><span style="font-size: 9pt">MFC除了定义程序执行结构之外,还定义了三种基本的主窗口模型:单文档窗口,多文档窗口和对话框作为主窗口。</span></p>
<p ALIGN="JUSTIFY"><span style="font-size: 9pt">Visual C++提供了两个重要的工具,用于支持应用程序框架,它们就是前面提到AppWizard和ClassWizard。AppWizard用于在应用程序框架基础上迅速生成用户的应用程序基本结构。ClassWizard用于维护这种应用程序结构。</span><b></p>
<p></b><span style="font-size: 9pt"><font color="#3973DE">2.4.3 MFC的优点</font></span></p>
<p><span style="font-size: 9pt">Microsoft MFC具有以下不同于其它类库的优势:</span></p>
<blockquote>
<p><span style="font-size: 9pt">完全支持Windows所有的函数、控件、消息、GDI基本图形函数,菜单及对话框。类的设计以及同API函数的结合相当合理。</span></p>
<p><span style="font-size: 9pt">使用与传统的Windows API同样的命名规则,即匈牙利命名法。</span></p>
<p><span style="font-size: 9pt">进行消息处理时,不使用易产生错误的switch/case语句,所有消息映射到类的成员函数,这种直接消息到方法的映射对所有的消息都适用。它通过宏来实现消息到成员函数的映射,而且这些函数不必是虚拟的成员函数,这样不需要为消息映射函数生成一个很大的虚拟函数表(V表),节省内存。</span></p>
<p><span style="font-size: 9pt">通过发送有关对象信息到文件的能力提供更好的判定支持,也可确认成员变量。</span></p>
<p><span style="font-size: 9pt">支持异常错误的处理,减少了程序出错的机会</span></p>
<p><span style="font-size: 9pt">运行时确定数据对象的类型。这允许实例化时动态操作各域</span></p>
<p><span style="font-size: 9pt">有较少的代码和较快的速度。MFC库只增加了少于40k的目标代码,效率只比传统的C
Windows程序低5%。</span></p>
<p><span style="font-size: 9pt">可以利用与MFC紧密结合的AppWizard和ClassWizard等工具快速开发出功能强大的应用程序。</span></p>
</blockquote>
<p> </p>
<p><span style="font-size: 9pt">另外,在使用MFC时还允许混合使用传统的函数调用。</span></p>
<p><span style="font-size: 9pt">我们着重讲解一下MFC对消息的管理,这是编写MFC消息处理程序的基础。</span><b></p>
<p></b><span style="font-size: 9pt"><font color="#3973DE">2.4.4 MFC对消息的管理</font></span></p>
<p><span style="font-size: 9pt">Windows消息的管理包括消息发送和处理。为了支持消息发送机制,MFC提供了三个函数:SendMessage、PostMessage和SendDlgItemMessage。而消息处理则相对来说显得复杂一些。MFC采用了一种新的机制取代C语言编程时对Windows消息的Switch/Case分支,简化了Windows编程,使程序可读性、可维护性大大提高。</span><b></p>
<p><span style="font-size: 9pt">MFC对消息的处理</span></b></p>
<p><span style="font-size: 9pt">MFC不使用用C语言编写Windows程序时用的易产生错误的switch/case语句,而采用一种消息映射机制来决定如何处理特定的消息。这种消息映射机制包括一组宏,用于标识消息处理函数、映射类成员函数和对应的消息等。其中,用afx_msg放在函数返回类型前面,用以标记它是一个消息处理成员函数。类若至少包含了一个消息处理函数,那么还需要加上一个DECLARE_MESSAGE_MAP()宏,该宏对程序执行部分所定义的消息映射进行初始化。清单2.3演示了消息处理函数的例子:</span><b></p>
<p><span style="font-size: 9pt">清单2.3 消息处理函数例子</span></b></p>
<p><span style="font-size: 9pt">class CMainFrame:CFrameWnd{</span></p>
<p><span style="font-size: 9pt">public:</span></p>
<p><span style="font-size: 9pt">CMainFrame();</span></p>
<p><span style="font-size: 9pt">protected:</span></p>
<p><span style="font-size: 9pt">//{{AFX_MSG(CMainFrame)</span></p>
<p><span style="font-size: 9pt">afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);</span></p>
<p><span style="font-size: 9pt">afx_msg void OnEditCopy();</span></p>
<p><span style="font-size: 9pt">afx_msg void OnClose();</span></p>
<p><span style="font-size: 9pt">//}}AFX_MSG</span></p>
<p><span style="font-size: 9pt">DECLARE_MESSAGE_MAP()</span></p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -