创建和销毁过程几个函数的执行顺序
发布日期:2022-01-31 02:37:25 浏览次数:114 分类:技术文章

本文共 3360 字,大约阅读时间需要 11 分钟。

1:对象生成后 函数执行顺序

首先执行 构造函数-> Create->PreSubclassWindow()->OnCreate()->OnInitDialog()

Create 创建窗口,发出WM_CREARE消息。  

OnCreate  响应WM_CREARE消息。

Create是创建对话框,OnCreate是响应Create操作的事件处理函数,OnInitDialog是对话框初始化函数

 

销毁对象时,函数的执行顺序

DestroyWindow()->OnDestroy()->析构函数

1. 点“确定”、“取消”时的关闭路由为 

OnOK()或OnCancel() ---> EndDialog() ---> DestroyWindow() ---> OnDestroy() ---> PostNcDestroy() 
2. 点“关闭”标题栏按钮的关闭路由为 
OnClose()---> DestroyWindow() ---> OnDestroy() ---> PostNcDestroy()

 

OnClose():消息响应函数,响应WM_CLOSE消息,当"关闭"按钮被单击的时候(而不是我们眼睛所见的对话框从屏幕上消失时),该函数被调用,用户在响应OnOk()或者OnCancel()函数之后,不会发送WM_CLOSE消息

OnDestroy():消息响应函数,响应WM_DESTROY消息,当一个窗口即将被销毁时,被发送

在单视图程序中,根据<<深入浅出MFC>>所讲,程序退出时执行的操作顺序为

(1)用户点击退出按钮,发送了WM_CLOSE消息
(2)在WM_CLOSE消息的处理函数中,调用DestroyWindow()
(3)在DestroyWindow()中发送了WM_DESTROY消息
(4)在WM_DESTROY消息中调用PostQuitMessage(),发送WM_QUIT消息,结束消息循环

综上,程序先调用OnClose()(也可能不调用),然后调用OnDestroy()(必调用),所以,如果要进行程序结束时的清理工作,应该在OnDestroy()中,而不是在OnClose(),否则就有可能会出现内存泄漏的危险了!

 

 

第一,OnOK()和OnCancel()是CDialog基类的成员函数,而OnClose()和OnDestroy()是CWnd基类的成员函数,即WM消息响应函数。从应用程序结构的角度,拿对话框来说,红色的X对应的是CWnd,而处于对话框中的“确定”、“取消”按钮则对应了CDialog。

第二,OnClose()和OnDestroy()

在单视图程序中,根据<<深入浅出MFC>>所讲,程序退出时执行的操作顺序为(从点X按钮开始)

(1)用户点击X退出按钮,发送了WM_CLOSE消息----->响应OnClose()
(2)在WM_CLOSE消息的处理函数中,调用DestroyWindow()----->销毁与指定CWnd窗口对象关联的窗口,但未销毁CWnd对象

(3)在DestroyWindow()中发送了WM_DESTROY消息----->窗口销毁后响应OnDestroy()

(4)在WM_DESTROY消息中调用PostQuitMessage(),发送WM_QUIT消息,结束消息循环

可以看到,程序的退出过程,是先响应OnClose(),然后响应OnDestroy(),在响应OnDestroy()之前,窗口对象已经被销毁。OnDestroy()到底干了什么呢?它就像一个teller,先通知CWnd对象告诉它即将被销毁,尔后OnDestroy的真正运行是在CWnd对象已经从屏幕上清除以后被调用的。

第三,OnOK()、OnCancel()()、OnClose()、OnDestroy()

CDialog::OnOK首先调用UpdateData(TRUE)将数据传给对话框成员变量,然后调用CDialog::EndDialog关闭对话框;   

CDialog::OnCancel只调用CDialog::EndDialog关闭对话框;   
OnClose()是响应   WM_CLOSE   的.一定程度上可以说CDialog::EndDialog()和OnClose()完成类似的工作,但处理的机制不一样,前者是CDialog的对象机制,后者是WM的消息映射机制。

CDialog::EndDialog()-------->OnDestroy()

                 OnClose()-------->OnDestroy()

EndDialog()和OnClose()属于“同级别”的,所以我们在按下OK按钮的时候,程序是不会执行OnClose()的,但两种机制都必须经过OnDestroy()。

 

要消除窗口对象,必须清楚窗口对象的构成.在一个通常的程序中,先创建c++窗口对象,然后由Windows创建实际的窗口结构,并返回句柄与c++对象连接.也就是说,窗口对象包含c++窗口对象和Windows窗口对象,两者通过句柄HWND联系. 

现在,让我们看看"正规"的窗口对象清除流程.所谓对象的清除是指释放对象所占的资源,窗口对象中Windows窗口对象占有的是系统资源,c++对象占 有的是内存资源.释放系统资源相对要简单一些:调用虚函数DestroyWindow删除Windows窗口对象.如果DestroyWindow删除的 是父窗口,Windows会自动为子窗口调用DestroyWindow.一般来说,程序不必调用DestroyWindow.因为当用户关闭窗口时, Windows便发送WM_CLOSE消息,WM_CLOSE的缺省消息处理函数CWnd::OnClose调用DestroyWindow. 
到这时,清除工作已经完成了一半,屏幕上的窗口已经不见了!但是别忘了,在内存中还有一个c++窗口对象.让我们再看看c++对象清除的过程:当 窗口被取消时,窗口最后发送的一个消息是WM_NCDESTROY.它缺省的消息处理函数CWnd::OnNcDestroy把c++窗口对象与句柄 HWND分离,并调用一个很重要的虚函数PostNcDestroy.这个函数是搞清窗口对象清除的关键.Cwnd中的PostNcDestroy什么都 不做.有些MFC窗口类会重载它,并加入delete this代码删除c++对象.这些窗口类常常是以new操作符建立在堆中的.由于重载了PostNcDestroy,使窗口有自动清除功能.因此,我们不 用关心清除问题了.另外的一些MFC窗口类一般是以变量形式创建的,MFC没有为也没必要为它们重载PostNcDestroy函数.

不具备自动清除功能的窗口类,一般在堆栈中创建或嵌入于其它c++对象中: 

所有标准的Windows控件类(如CStatic, CEdit, CListBox等等) 
由CWnd类直接派生出来的子窗口对象(如用户定制的控件) 
拆分窗口类(CSplitterWnd) 
缺省的控制条类(CControlBar的派生类) 
对话框类(CDialog)在堆栈上创建的模态对话框类 
所有的Windows通用对话框(除CFindReplaceDialog) 
由ClassWizard创建的对话框 
具有自动清除功能的窗口类,一般在堆中创建: 
主框架窗口类(直接或间接从CFrameWnd类派生) 
视图类(直接或间接从CView类派生) 
从某种程度上来说,MFC的"服务到家"使初学者有些找不着北.不过,不得不承认:MFC干的很漂亮! 
谈到这里,我们应该明白c++里一条重要的准则:用DestroyWindow清除窗口对象,不要用"delete". 
对于不具备自动清除功能的窗口类使用"delete"时,"delete"先调用析构函数里的DestroyWindow,由于在析构函数中,虚 机制不起作用,这里只能调用本地版本(Cwnd类)DestroyWindow函数,显然这不是我们想要的.对于有自动清除功能的窗口类,好象问题更严重 一点,前面提到了重载的PostNcDestroy已经含有了"delete this",这样c++对象就被释放了两次. 

转载地址:https://blog.csdn.net/LJH0600301217/article/details/46454675 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:距离变换的理解
下一篇:Unicode字符集下CString与char *转换

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年03月26日 06时59分21秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

mysql select同时update_MySQLSELECT同时UPDATE同一张表 2019-04-21
mysql删除后数据库没变化_mysql之delete删除记录后数据库大小不变 2019-04-21
net mysql start3534_MySQL 5.7.14 net start mysql 服务无法启动-“NET HELPMSG 3534” 的奇怪问题... 2019-04-21
pta两个有序链表的合并_7-1 两个有序链表序列的合并 (20分) --- 内存问题再叙 2019-04-21
python问题描述怎么写_python写文件有时候写不进去怎么办 2019-04-21
qpython3安装lxml_在python的lxml中使用xml目录? 2019-04-21
java 幂取模_快速幂取模算法 2019-04-21
java build path jre_java-如何在安装了jre 7后为Jre 6设置路径? 2019-04-21
java上传下载源码_javaweb简单实现文件上传与下载源代码 2019-04-21
java socket udp 广播_1.Java 的屏幕广播(基于UDP),2.多线程下载器 2019-04-21
java控制热敏打印机的例子.rar_stm32控制热敏打印机 2019-04-21
java clone equals_(原)java中对象复制、==、equals 2019-04-21
java滚动字幕实训报告_Java实习报告 (7000字).doc 2019-04-21
java mysql utils_MySQL_(Java)提取工具类JDBCUtils 2019-04-21
java取后两位_java中取小数点后两位(四种方法) 2019-04-21
java统计插件_[Java教程]编写maven代码行统计插件 2019-04-21
3des java ivparame_求高手看看des的加密问题 2019-04-21
autocad2014 连接mysql_auto mysql 2019-04-21
bash 将二进制转换为十进制_Bash脚本 - 读取二进制文件 2019-04-21
java一箭穿心的代码_Java打印一箭穿心 2019-04-21