mfc中的消息莫是相对于虚函数表来说到底有什么优势?有人说是空间上面有好处。既可以省下长长的虚函数表的内存。比如:
用虚函数的话,window的基类会是
class window
{
virtual OnSize() = 0;
virtual OnMove() = 0;
virtual OnContextMenu() = 0;
……等等
}
可想而知,每个由此继承而来的子类将会负担多么大的虚函数表,光是windows自带的就有数十个之多。当然不可取。
可是除此之外,似乎有一种观点是如果机器够快的话就可以采用虚函数的方法了,哪只不不过是ms在当年的无奈之举。嗬嗬,真的是这样吗?非也!
其一、如果有自定义的消息怎么办?修改基类?
其二、其实在窗口间互相传递消息可以看成是互相的请求服务,此服务被请求窗体可以响应,也可以不响应。这种灵活性是虚函数方法所无法取得的——如果不支持的话,嗬嗬,对不起,编译时便会报错了。请求方对于被请求方的所有要求仅仅是其是CCmdTarget的子类即可。怎么样,正所谓便宜实惠量又足啊。可就是不太好理解,所以ms提供了许多宏来做这件事情。
下面看一个具体的例子。这是一个关于treectrl操作的例子。这是一棵表示公司组织的树,上面的节点有
公司
----人事科
-----张三
-----李四
----采购
-----王二
-----麻子
即三类节点,公司、科室、员工
当客户右击鼠标时,对于不同的节点弹出的菜单当然是不同的。
做法1、判断三种节点的图标,(假定用不同的图标显示不同节点)然后针对不同的情况弹出菜单。这种方法对于显然不妥,有点像经典的
if ( obj.typeid == ...)
do something
else if ( obj.typeid == .. )
do somthine else ...
结果就是在treectrl的代码中充满了这样的判断代码
做法2、有class Company, class office, class person,均从CCmdTarget继承。当insert treeitem的时候,产生对象,将其指针和插入的item联系起来,方法可以采用SetItemData(对象的指针),这样的话,处理弹出菜单的方法就变为
treectrl::OnContextMenu(...)
{
CCmdTarget* p = GetItemData(hSelItem);
p->sendcommand(wm_contextmenu, point)
}
这样就ok了。但是有一个缺点,占用太多的内存了!每个item都有多出sizeof(CCmdTarget),有点过分。
再改进——做法3
class Company, office, person不变,
但增加他们的工厂类
class treeitemor
{
virtual CCmdTarget* CreateItem() = 0;
}
class Companyor
{
long m_ID;
virtual CmdTarget* CreateItem(); //产生Company类
}
class office和person同上
弹出菜单变为
treectrl::OnContextMenu(...)
{
treeItemor* ItemCreator = GetItemData(hSelItem);
CCmdTarget *pCmd = ItemCreator->CreateItem();
pCmd->SendCommand(WM_CONTEXTMENU, POINT);
}
呼!总算完了。最后请大家多提意见!
本文地址:http://com.8s8s.com/it/it2208.htm