函数何解之(DWORD) (m_pStoreMap)[ (void )pClassRef ]

      侯捷老师的深入浅出MFC里有一点,我想了半天才想明白!现在记录一下思路!

    如同图上画红色图线的那个函数!(DWORD) (*m_pStoreMap)[ (void *)pClassRef ],这个东西看了好久,愣是没有看懂!不过后来看了一下CArchive中关于m_pStoreMap的定义,如下:

 

    看见没,m_pStoreMap是一个CMapPtrToPtr类型的指针,这个类可能大家比较陌生,我在这里稍微查了一些资料,描述如下:

 

    会用CMap了,CMapPtrToPtr也会用了,很容易理解。

    映射表类(CMap)是MFC集合类中的一个模板类,也称作为“字典”,就像一种只有两列的表格,一列是关键字,一列是数据项,它们是一一对应的。关键字是唯一的,给出一个关键字,映射表类会很快找到对应的数据项。映射表的查找是以哈希表的方式进行的,因此在映射表中查找数值项的速度很快。举个例子来说吧,公司的所有职员都有一个工号和自己的姓名,工号就是姓名的关键字,给出一个工号,就可以很快的找到相应的姓名。映射类最适用于需要根据关键字进行快速检索的场合。

 

CMapWordToPtr 保存void指针,关键字为WORD

CMapPtrToWord 保存WORD,关键字为void指针

CMapPtrToPtr 保存void指针,关键字为其它void指针

CMapWordToOb 保存CObject指针,关键字为WORD

CMapStringToOb 保存CObject指针,关键字为字符串

CMapStringToPtr 保存void指针,关键字为字符串

CMapStringToString 保存字符串,关键字为字符串

 

     因此,m_pStoreMap其实是指向一个映射表的指针!这个映射表键值(key)是(void *)类型的,同时其值(value)也是(void*)类型的。当然可能你会问为什么上面的m_pStoreMap要定义成枚举类型,好吧!这与现在的问题无关,我们等会再说!

     对于这个式子,我们慢慢分解,(DWORD) (*m_pStoreMap)[ (void *)pClassRef ],由于pClassRef是CRuntimeClass*类型的,所以自然而然,前面的(void*)起到了强制转换的作用,根据我们对于指针的理解,自然(*m_pStoreMap)代表了一个CMapPtrToPtr类型的首地址CMapPtrToPtr复写了[]运算符,现在脉络就很清晰了,(*m_pStoreMap)[ (void *)pClassRef ]表示从(*m_pStoreMap)这个映射表里找到键值为 (void *)pClassRef 的对应的值(value),自然这个值也是(void*)类型,所以在前面要加上强制转换符(DWORD)。

 

     这个式子算是理解清楚了,我其实一直不明白为什么要这样弄?

 

     侯捷老师的书这章我看了几遍,还是没弄懂,直到最近用vs调试了一下,才明白了意图!

假设我们现在是画完了一幅图,准备保存,好,我现在在CArchive::WriteClass这个函数里面设了一个断点!

 

     上面的那一些函数调用我们都不管,我们看关键的几步!

 

     好吧,至少现在这个函数(MapObject)什么都没做!我断点运行了一遍!但是这确实是很重要的一个函数,我在后面会提及!现在大家可以不管!

   (在这里这个函数的作用是初始化映射表,如果m_pStoreMap为NULL,就创建一个CMapPtrToPtr给m_pStoreMap,并且在里面就已经放入了一个初始值!NULL对应(void*)(DWORD_PTR)wNullTag,当然wNullTag被宏定义为0,并将m_nMapCount 赋为1

 

 

    接下来继续运行,也就是运行到(DWORD) (*m_pStoreMap)[ (void *)pClassRef ]这一句了,很明显,我们并未有在里面存储索引值(void *)pClassRef的值,查阅MSDN,我知道了,如果(*m_pStoreMap)里面没有这个索引的话,会返回void,也就是0,这个if不成立,运行到else处,我截一下代码!

 

     侯捷老师的书里面丢了一句我认为比较重要的句子没写,那就是我上面画横线的一句,

     (*m_pStoreMap)[(void*)pClassRef]=(void*)(DWORD_PTR)m_nMapCount++;

     这一句的意思很明显了,那就是将值存进去,也就是如果是一个新类的话,就将键与值存入映射表,千万别忘了那些个类里面的CRuntimeClass可是static类型,也就是同一个类的CRuntimeClass*都是一个常值,这里也就建立了关系!

     好吧!下一次如果我要存一个相同的类,那么运行至(DWORD) (*m_pStoreMap)[ (void *)pClassRef ]这一句的时候就会读出一个不为0的值了!

     现在与侯捷老师说的就联系起来了!噢耶!

 

     再普及一个知识点!你看侯捷后面写了几个类的时候是不是很奇怪?为什么存第二个新类的时候,索引值(nClassIndex)变成了3,第三个新类是变成了5,我们回过头来看看调用WriteClass函数的WriteObject就知道了。

 

  备注:

   1.看到没,调用完WriteClass之后,WriteObject立马又把pOb也就是传进来的类指针这个key和对应的value加到Map里面去了,并且m_nMapCount++,第一次存完新类之后,这个值就变成了3!

   2.也就是说,每一次存储新类的时候都要存两个,一个是pOb->GettimeClass()和pOb本身,后面的m_nMapCount一共加2次!

   3.顺便提两句,m_pStoreMap是在这里被赋值的,这里完成m_pStoreMap的初始化工作,先new一个CMapPtrToPtr,然后赋给m_pStoreMap,然后往里面存一个初始的值!并将m_nMapCount置为1.在后面的WriteClass里面虽然也调用MapObject(NULL),但是由于已经初始化了,那里面基本上什么也没做!好了,解释得已经比较清楚了!噢耶!

 

    Ps:我用的是VS2012模拟的,其实变化也不是很大!有一些地方与书上不同,但是大体一致!

    至于为什么上面的m_pStoreMap要定义成枚举类型,我来解释一下:

union

{

    CPtrArray* m_pLoadArray;

    CMapPtrToPtr* m_pStoreMap;

};

    我们知道CArchive只有有两个“状态”,存储和读取,用以个union分别表示不同状态时的成员:

    CPtrArray* m_pLoadArray; //Store时不使用

    CMapPtrToPtr* m_pStoreMap; //Load时不使用

    共用类型的唯一好处就是节约内存!既然两个变量在任意时刻只使用一种,那么自然,就可以两个变量共享同一块内存!

    博客里面的图片不够清晰,我给大家一个doc文档吧!

    http://pan.baidu.com/s/1hqhyQ1Y


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值