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

如果MFC的消息映射表需要排序…

2012年11月07日 ⁄ 综合 ⁄ 共 1195字 ⁄ 字号 评论关闭

这是今天下班前和同事讨论的问题。

MFC的消息映射通过几个简单的宏,对Windows的消息机制做了非常好的面向对象封装,一时为无数C++程序员所模仿(当然,MFC可能也是模仿别人的)。熟悉MFC消息映射机制的人都知道,其本质无非就是把消息和其处理函数放到一个数组当中,当程序接收到某消息时,就会遍历该数组,查找对应的消息ID,找到了就调用其处理函数,找不到就往其基类的数组当中去找。

对,是线性查找!那么为什么MFC没有将消息数组排序,然后用二分查找,把复杂度从O(n)提高到O(lg n)呢?原因我想可能是没有必要,可以想像,一个类中的消息处理函数的个数是十分有限的,假设有100个消息,最坏情况也就是比较100个整数,其效率影响也是非常小的。而为了这不必要的效率在Framework级别加入排序与二分查找的算法,无疑增加了不必要的代码复杂度。

 

那么假设现在让你实现对消息映射表的排序,该如何来做呢?

因为消息映射表是全局变量,在Winmain之前就已经建好了,所以可以在Winmain的最开始做这个排序动作;但是MFC是封装了Winmain的,你无从修改,所以应该放在CWinApp::InitInstance()中;但是我们好像无法在这么一个统一的地方,访问到所有的MFC类的消息映射表并对其进行排序 - CRuntimeClass应该也无法完成这个任务,而且在非serialize的MFC程序中,其CRuntimeClass是没有连在一个链表中的,所以连访问CRuntimeClass都有问题。

另外一个想法是在接收到一个消息之后,但在dispatch之前对消息映射表进行排序,这个地点就是CCmdTarget::OnCmdMsg,这是个好方法,只需对用到的那个类进行排序,有点lazy evaluation的味道。 但是我们不能每次调用都排序一遍,那就势必需要一个static的变量来标志该消息映射表是否有序,可以这么做,在message map的宏实现中,额外插入一个初始值为false的static bool变量,和一个Sort的虚函数用来对消息映射表进行排序(调用一个公用的排序函数),并设置标志位,这样在CCmdTarget::OnCmdMsg调用该Sort虚函数就完成了排序。但这样有个缺点,就是每个类都多了一个额外的虚函数,对size和performance都有些影响。其实我们还可以复用消息映射表来存储这个标志位 - 因为每个类都会对应一个消息映射表,所以只要在每个类的消息映射表的第一项插入是否有序的标志,在CCmdTarget::OnCmdMsg中直接通过GetMessageMap虚函数拿到当前类的消息映射表,检验第一项标志位是否为排序,如果为否则排序,否则继续,句号。当然,这里有一点要注意的是把消息映射表的第一项挪做他用了,Framework的其他地方不会误解而当做普通项来使用。

 

抱歉!评论已关闭.