首页 > 代码库 > MFC六大核心机制之一:MFC程序的初始化

MFC六大核心机制之一:MFC程序的初始化

 

       MFC六大核心机制概述

       我们选择了C++,主要是因为它够艺术、够自由,使用它我们可以实现各种想法,而MFC将多种可灵活使用的功能封装起来,我们岂能忍受这种“黑盒”操作?于是研究分析MFC的核心机制成为必然。

       首先,列出要讲的MFC六大核心机制:

       1、MFC程序的初始化。
       2、运行时类型识别(RTTI)。
       3、动态创建。
       4、永久保存。
       5、消息映射。
       6、消息传递。

     

C++代码
  1. #include <afxwin.h>   
  2. class MyApp : public CWinApp   
  3. {   
  4. public:   
  5. BOOL InitInstance()  //②程序入点   
  6. {   
  7.   CFrameWnd *Frame=new CFrameWnd();//构造框架   
  8.   m_pMainWnd=Frame; //将m_pMainWnd设定为Frame;   
  9.   Frame->Create(NULL,"最简单的窗口");//建立框架   
  10.   Frame->ShowWindow(SW_SHOW);  //显示框架   
  11.   return true;         //返回   
  12.  }   
  13. };   
  14. MyApp theApp;  //①建立应用程序。  

       设定链接MFC库,运行,即可看见一个窗口。首先我们要弄明白,VC++不是一种语言,它就象我们学c语言的时候的一个类似记事本的编辑器(请原谅我的不贴切的比喻),所以,在VC里面我们用的是C++语言编程,C++才是根本(初学者总是以为VC是一门什么新的什么语言,一门比C++先进很多的复杂语言,汗)。说了那么多,我想用一句简单的话概括“MFC黑箱’,就是为我们的程序加入一些固化的‘C++代码’的东西”。

     CObject->CCmdTarget->CWinThread->CWinApp->自己的重写了InitInstance()的应用程序类。
       CObject(同上)->CCmdTarget(同上)->CWnd->CFrameWnd

CWinApp类或者它的基类CCmdTarget里面应该有一个虚函数virtual BOOL InitInstance(),是的,因为那里是程序的入口点,初始化程序的地方,那自然少不了的。可能有些朋友会说,反正InitInstance()在派生类中一定要重载,我不在CCmdTarget或CWinApp类里定义,留待CWinApp的派生类去增加这个函数可不可以。扯到这个问题可能有点越说越远,但我想信C++的朋友对虚函数应该是没有太多的问题的。总的来说,作为程序员如果清楚知道基类的某个函数要被派生类用到,那定义为虚函数要方便很多。

       也有很多朋友问,C++为什么不自动把基类的所有函数定义为虚函数呢,这样可以省了很多麻烦,这样所有函数都遵照派生类有定义的函数就调用派生类的,没定义的就调用基类的,不用写virtual的麻烦多好!其实,很多面向对象的语言都这样做了。但定义一个虚函数要生成一个虚函数表,要占用系统空间,虚函数越多,表就越大,有时得不偿失!这里哆嗦几句,是因为往后要说明的消息映射中大家更加会体验到这一点,好了,就此打往。

2、WinMain()函数和CWinApp类

       大家再往下想,我们还要我们MFC“隐藏”更多的东西:WinMain()函数,设计窗口类,窗口注册,消息循环,回调函数……我们马上想到封装想封装他们。大家似乎隐约地感觉到封装WinMain()不容易,觉得WinMain()是一个特殊的函数,许多时候它代表了一个程序的起始和终结。所以在以前写程序的时候,我们写程序习惯从WinMain()的左大括写起,到右大括弧返回、结束程序。

       我们换一个角度去想,有什么东西可以拿到WinMain()外面去做,许多初学者们,总觉得WinMain()函数是天大的函数,什么函数都好象要在它里面才能真正运行。其实这样了解很片面,甚至错误。我们可以写一个这样的C++程序:

C++代码
  1. ////////////////////////////////////////////////////   
  2. #include <iostream.h>   
  3. class test{   
  4. public:   
  5.  test(){cout<<"请改变你对main()函数的看法!"<<endl;}   
  6. };   
  7. test test1;   
  8. /**************************/  
  9. void main(){}   
  10. ////////////////////////////////////////////////////  

       在上面的程序里,入口的main()函数表面上什么也不做,但程序执行了(注:实际入口函数做了一些我们可以不了解的事情),并输出了一句话(注:全局对象比main()首先运行)。现在大家可以知道我们的WinMain()函数可以什么都不做,程序依然可以运行,但没有这个入口函数程序会报错。

 

 那么WinMain()函数会放哪个类上面呢,请看下面程序:

C++代码
  1. #include <afxwin.h>   
  2. class MyApp : public CWinApp   
  3. {   
  4. public:   
  5.  BOOL InitInstance()  //②程序入点   
  6.  {   
  7.   AfxMessageBox("程序依然可以运行!");   
  8.   return true;   
  9.  }   
  10. };   
  11.   
  12. MyApp theApp;  //①建立应用程序。  

       大家可以看到,我并没有构造框架,而程序却可以运行了——弹出一个对话框(如果没有WinMain()函数程序会报错)。上面我这样写还是为了直观起见,其实我们只要写两行程序:

       #include <afxwin.h>
       CWinApp theApp;     //整个程序只构造一个CWinApp类对象,程序就可以运行!

       所以说,只要我们构造了CWinApp对象,就可以执行WinMain()函数。我们马上相信WinMain()函数是在CWinApp类或它的基类中,而不是在其他类中。其实这种看法是错误的,我们知道编写C++程序的时候,不可能让你在一个类中包含入口函数,WinMain()是由系统调用,跟我们的平时程序自身调用的函数有着本质的区别。我们可以暂时简单想象成,当CWinApp对象构造完的时候,WinMain()跟着执行。

       现在大家明白了,大部分的“通用代码(我们想封装隐藏的东西)”都可以放到CWinApp类中,那么它又是怎样运行起来的呢?为什么构造了CWinApp类对象就“自动”执行那么多东西。

       大家再仔细想一下,CWinApp类对象构造之后,它会“自动”执行自己的构造函数。那么我们可以把想要“自动”执行的代码放到CWinApp类的构造函数中。

 

请允许我把手按在圣经上声明一下:WinMain()不是普通的函数,它要肩负着初始化应用程序,包括全局变量的初始化,是由系统而不是程序本身调用的,WinMain()返回之后,程序就结束了,进程撤消