现在的位置: 首页 > 综合 > 正文

MFC程序执行流程小结

2013年11月06日 ⁄ 综合 ⁄ 共 3582字 ⁄ 字号 评论关闭

1 半月多的从0开始的MFC学习总结  

       寒假来了,要开始涉及MFC程序了(2013-01-12),没有看过一天关于C++的书籍。我比较有勇气(当然是在有老师指导的情形下,老师常给予关键性的启发),直接打开VS2010寻找创建VS MFC程序项目的步骤,在知道用VS 创建MFC程序步骤后(其实这个非常简单,很多都是默认选项),赤裸裸的开始研究MFC的代码结构。对于一个对MFC毫无概念的初学者来说,首先我给自己规定的是先学会怎么在MFC框架中成功的写入自己的代码。第一眼瞧见MFC程序的时候,对于每个类都独占一个头文件和源文件的现象倒是不奇怪:至少学过几天C语言,也用C语言在黑莓平台上面开发过一个小小小小的游戏;但扔令我奇怪的是:

  • MFC程序运行时的入口在哪里?

赶快在谷歌中输入MFC程序相关,才知道MFC程序运行入口点在主程序应用类定义对象时被引起,而这些都是经过封装的。当时看得云里雾里的,就逼迫自己去相信这样一个事实:程序的入口由编译器自动给予。

  • MFC中每个函数(后来才知道那是函数)怎么都那么奇怪,前面还有两个冒号?

其实这就只是MFC中编写函数时的一种格式而已:前面是函数类型和类名,中间是冒号,后面是类中的成员函数。这跟在C语言中的自定义函数编写差不多。在学习过程中只要弄清楚这一点即可。

  • MFC程序是怎么响应用户的各种消息的呢?

又到谷歌中进行相关搜索,方模糊知道在定义主程序应用类对象时会进入AfxWinMain函数(相当于C语言中的main函数),在这个函数内有消息循环的代码,随时监测用户所给予的事件并调用相应的函数去处理。

  • 那如何在MFC中添置代码?
VS的类向导能很好的帮助初学者解决这个问题。不过也是需要用心去好好发现的。当用VS类向导给某个按钮添加事件响应函数时,要注意到类向导还往类中声明了事件响应函数,在BEGIN_MESSAGE_MAP()....END_MESSAGE_MAP间还添加了相应的响应事件类型的消息宏(宏中有规定当此事件发生时调用哪一个函数)。当知道MFC调用函数是应用这个机制(至少这些都是不可少的步骤)后,就可以在类中添加自定义函数成为此类的新成员函数,这个时候我就应该明白,我还需要在BEGIN_MESSAGE_MAP()....END_MESSAGE_MAP中添加此函数响应事件的类型,然后还需要编写函数代码。当然在头文件中要允许响应事件才行(添加DECLARE_MESSAGE_MAP()语句)。知道这些后,编写windows常用控件程序就够了。老师建议我先基于对话框程序,编写windows常用控件的程序,在经过静(动)态按钮、可编辑框(含数据交换)、组合框、滚动条、菜单工具栏等常用windows控件编程以后,在MFC中添加代码的流程就已经比较熟悉了,还顺便熟悉了资源属性设置块。
到了这一步之后,我感觉对MFC类很不熟悉,以至于对类中的成员函数和数据成员的利用十分不充分。不过老师说,长期使用后就熟悉了。我听后觉得有道理,只是马上就要放假回家了,把熟悉MFC库使用作为短时间内的目标是不可能的。所以,我回过头来,去看MFC程序执行流程到底是怎么进行的,现在看来,这个决定对我后期的MFC深入学习是有极大的帮助的。
 

2 MFC程序执行流程

对于理解MFC程序执行流程,我觉得理解new 、虚拟函数调用构造和析构函数调用(http://blog.csdn.net/misskissc/article/details/8549254)次序、类指標结论几个地方对此很有帮助。刚好在学习MFC程序的过程中也正好去学习了这几个方面(或者说是先去查询式的学习了这几个方面之后觉得对理解MFC程序执行流程有帮助)。

2.1new

new和malloc函数都可以为变量申请一段某种类型的动态存储空间,new在申请动态空间外还会引发申请空间对象构造函数的运行。当然,有new就需要在需要的地方有delete,这是一种必备的习惯。
 

2.2虚拟函数的调用

使用派生类对象访问类的成员函数时,若此函数为非虚拟函数时,访问的函数都是基类成员函数的地址;若访问的成员函数为虚拟函数(前面加了virtual关键字)时,若在派生类中没有申明(修改)则调用的是基类(或者某派生类(当此派生类改变了此虚拟函数时))中的函数地址,若在派生类修改了虚拟函数,则调用的就是派生类的成员函数。
 

2.3构造函数和析构函数的调用次序

构造函数和析构函数的调用次序从一定程度上反应出MFC程序执行流程。建构式(运行应用程序类的对象的构造函数)是早于程序运行入口点的,即应用程序类对象的构造函数的运行要比AfxWinMain函数的运行要早。当然,析构函数是在相应情况下(delete发生、局部运行完毕、程序运行结束时)发生。而且构造函数的运行遵循一定的方式(构造函数析构函数调用次序),析构函数的运行与构造函数的运行相反。
 

2.4类指標相关结论

  • 如果以一个基础类别之指标指向衍生类别之物件,那么该指标只能呼叫基础类所定义的函式。
  • 如果一个衍生类指标指向一个基础类别物件,必须先做明确的转型动作(对基础类之物件取地址&对派生类指标赋值)。这种做法很危险。
  • 如果基础类别和衍生类别都定义了相同名之成员函式,那么透过物件指标呼叫成员函式时,到底呼叫到哪一个函式,必须视该指标原始性别而定,而不是视指标实际所指之物件的性别而定。
  •  

    3 简析MFC程序执行流程

    撇开所有的头文件中对类声明、派生的代码,我们到应用程序类源代码文件(CMy*.cpp)定义应用程序类对象的地方,见图1
    图1.《深入浅出 MFC》一书中的MFC程序执行流程分析图
    MFC程序执行流程跟标号增大的方向一致:
    1. 当定义应用程序类对象时,在程序进入AfxWinMain()函数前,应用程序类对象的构造函数先运行,构造应用程序类对象。
    2. 进入程序运行的入口点AfxWinMain()函数中,AfxGetApp()函数返回指向当前应用程序的单一的CWinApp对象的指针。根据类指標相关结论可知,除了被修改的虚拟函式外,用指针pApp访问的函数都是访问的CWinApp中的成员函式。所以用pApp->InitApplication()  [及Run] 调用的函式为CWindApp::InitApplication() [及CWindApp::Run()] ;因为InitIntance()函数被改变,因此而pApp->InitIntance()调用的却是派生类中(假设为CMyWindApp)的函式(CMyWindApp::InitIntance()),而且InitIntance()函数内的内容会被自动执行,一般这里的代码为跟生成窗口有关。
    3. 这里是关于初始化的函数,作为初学者,这里可以先跳过。容日后究。
    4. 这就是在调用派生类CMyWindApp的成员函数,虽然这个调用的语句我们看不到。这里涉及虚拟函数妙用的内容哦,派生类中被修改的虚拟函数将会被调用。
    5. (5-8语句)这是在对虚拟函数InitIntance()进行改写,在改写的过程中很可能依据函数的调用方式(虚拟函数,非虚拟函数的调用方式)再调用其它的函数。其实函数的调用占MFC应用程序执行流程的很大一部分,对于函数的调用,这里添加了一些规则,如此就构成了整个的运行。
    6. (9语句)pApp->Run()就是检测是否有消息发生的主消息循环事件函数,当有任何规定的事件发生它都会检测到,并通过一定方式调用到相应的函数,具体内容可以后深究。
    这个过程只是在定义应用程序类对象时MFC内部机制的简单剖析,其实在接收到用户信息、调用用响应的事件函数(DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC巨集)等这些过程都是很有研究价值的,对咱初学者来说就先了解一个大概,最开始就要把这些原理弄得很清楚还是很费功夫的!如此,就找到了MFC程序入口及消息循环的基本原理了,至于MFC程序如何响应事件及另外的一些重要性质就让我们日后挖掘吧。个人觉得觉得明白MFC程序的内部执行流程机制还是得用一个比较漫长的阶段慢慢积累。不过明白以上的笔记之后对MFC继续学习和编写简单的小应用程序还是有帮助的。
     

    4 学习小结

    其实我们随时面临着快速掌握新知识的挑战,如何才能做到有”快速“这一点呢。我把此时觉得重要的几点记录如下:
    1. 基础。包括与新学知识相关的基础(如学C++前C语言还学得不错)和学习素养(首先是能静下心来看书,其次是能获取书中所描述的重点)的基础。
    2. 毅力。吃苦耐劳,坚持不懈怠。但也要讲究一定的方法,如常说的一个问题要是20分钟后都还没有丝毫解决那就去散散步吧,但散步这个小插曲丝毫不要影响对继续探究问题 的不离不弃的精神。
    3. 心态。不要太着急。不要太功利,脚踏实地(这不与快速冲突)掌握好每一个关键。

    此次笔记记录完毕。

    抱歉!评论已关闭.