VC++/MFC消息映射机制(2):MFC消息路由原理

VC++/ MFC消息映射机制(2):模仿MFC的消息路由

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

本文需结合上一篇文章《MFC消息映射原理》阅读。

消息路由的目的就是把当前类没有处理的消息,上传给其父类进行处理,一直传递到最顶级父类进行处理。
本小节应注意区别本文所指的消息映射和消息映射表的概念,在本小节,消息映射指的是<消息,处理函数>对,即程序中的ss数组,消息映射只保存了消息和函数的关系。而消息映射表指的是程序中的msgmp变量,消息映射表不但保存有消息映射(即ss),而且保还保存了其子类与父类的链表关系。
一、直线(消息)路由
在这里插入图片描述

1、直线路由:指的是若子类没有调用的函数的定义,则查找父类中是否有该函数的定义,一直向上直至查找到顶级父类。比如,假设A是顶级父类,D是最终的子类,继承关系为A→B→C→D,则D md; 则调用md.f();首先查找D中是否有该函数,若没有则再查找父类C,直至查找到顶级父类A为止。如右图所示。其实使用C++的继承或虚函数机制就可以直接实现直线路由,但由于处理窗口时需要映射消息与消息处理函数,而且在调用时不知道处理消息函数的名称,所以实际在MFC之中消息的直线路由经过了一系列的算法才实现的。
2、下面以示例说明MFC中消息直线路由的算法,为避免MFC的复杂性及MFC模仿时产生的大量警告信息,以下示例以C++程序(即VC++编译器应创建“控制台应用程序”)进行演示,主要为了说明MFC消息路由的原理。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

请按如下输入进行测试
1、输入1时,调用类A的f1,依次输出A,X,FA,因为ON(1,f1) 中1与f1对应,而f1在类A的各子类都未定义。
2、输入3原理与输入1类似。
3、输入4时(直线消息路由),调用类D中的f4,依次输出A,X,X,X,Y,A,X,FD。由此可见for循环执行了两次(输出了两次A),while循环执行了4次(输出了4次X)。分析如下:
1)、第一次for循环,检查最终子类E的消息映射表E::msgmp,然后依次对E::msgmp中的成员pss进行逐个检查以判断ON(4,f4)是否在类E之中进行了相关的映射(或者说检查类E的成员数组ss中,是否有值为{4,f4}的元素),最终的结果是映射ON(4,f4)未在类E之中,此时第一轮for循环结束,其中while循环共执行3次(输出3个X),因为在类E之中有3个ON映射(或者说类E的成员数组ss有3个元素),输出Y是因为while循环结束后未对s2赋值,此时s2=0。
2)、然后进行第二次for循环,检查其父类D的消息映射表D::msgmp(此时消息向上路由至父类D),然后对D::msgmp中的成员pss进行逐个检查以判断ON(4,f4)是否在类D之中进行了相关的映射,最后找到该映射,调用f4,输出FD,此时while循环一次(输出一个X),因为查找一次就找到了ON(4,f4)映射。
4、输入2的原理与输入4类似。
5、若输入1~5之外的其他字符,则依次输出AXXXXYAXYAYAYAY,共输出5个A(因为继承关系含有5个类),原理请读者自行分析。

在这里插入图片描述

二、拐弯路由

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

程序执行结果的原理分析:
假设消息由类C进入,并输入值6,程序输出:AXY AXY AY AXXY AXY AY AX FF。其中输出Y表示未查找到消息,程序按如下步骤执行:
1、调用全局函数::gg(),并执行其中的语句pa->g1(i);因此时pa=new C();因此调用类B中的B::g1()函数。
2、执行B::g1()中的第一条语句if(g(i)),此时this指针指向的是new C(),因此函数A::g()首先查找类C继承子树(即C,B,A三个类),并首先从类C开始查找消息,程序进入A::g();
3、在A::g()中,因为在类C继承子树中的类C、类B、类A中都未找到匹配的消息,所以程序会输出三个Y,又由于类C的继承子树有3个类,所以会执行三次for循环,所以会输出3个A,由于类A的ON()宏中的msgid的值为0,因此在while循环内,不会输出由类A产生的X,程序最终输出2个X,因此查找完类C继承子树后的输出结果为AXY AXY AY
4、在继承子树C、B、A中未找到匹配的消息,程序返回到B::g1()中,继续执行其后的下一条语句,pa=new E(); if(pa->g(i)) return 1; 由此可知,程序转入类E继承子树(即E、D、A),并从类E开始查找是否有匹配的消息(注意,消息在此时已经进行了拐弯),此过程与类C继承子树类似,程序最后输出AXXY AXY AY,第一个AXXY是查找类E时输出的,因为类E添加了两个ON宏,所以输出两个X。
5、查找完类E继承子树后,程序返回B::g1(),并继续执行其后的语句pa=new F(); if(pa->g(i)) return 1; 此时的过程与4相同,但在类F中找到匹配的消息,程序最后输出AXFF,程序结束。
6、输入6之后,程序最后在类F中找到匹配的消息,并最终输出AXY AXY AY AXXY AXY AY AX FF,输入其他值,和消息从其他类进入时的原理与此类似,请读者自行测试并分析。

对MFC消息路由的源码分析时,还要明白钩子函数的原理。

本文作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值