MFC 序列化再理解

 
   
 if (pOb =
  
 
   
本人在阅读CArchive源代码时遇到问题,请求高手解答....
首先,先看我给出的代码CArchive::WriteObject 和 CMapPtrToPtr::operator[]等..。
void CArchive::WriteObject(const CObject* pOb)
{
 ......//
if (pOb == NULL)
 {
 
   
// save out null tag to represent NULL pointer
  *this << wNullTag;
 }
 else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0)
  // assumes initialized to 0 map
 {
  // save out index of already stored object
  if (nObIndex < wBigObjectTag)
   *this << (WORD)nObIndex;
  else
  {
   *this << wBigObjectTag;
   *this << nObIndex;
  }
 }
 else
 {
  // write class of object first
  CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
  WriteClass(pClassRef);

  // enter in stored object table, checking for overflow
  CheckCount();
  (*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;

  // cause the object to serialize itself
  ((CObject*)pOb)->Serialize(*this);
 }
}



void*& CMapPtrToPtr::operator[](void* key)
{
 ASSERT_VALID(this);

 UINT nHash;
 CAssoc* pAssoc;
 if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
 {
  if (m_pHashTable == NULL)
   InitHashTable(m_nHashTableSize);

  // it doesn't exist, add a new Association
  pAssoc = NewAssoc();

  pAssoc->key = key;
  // 'pAssoc->value' is a constructed object, nothing more

  // put into hash table
  pAssoc->pNext = m_pHashTable[nHash];
  m_pHashTable[nHash] = pAssoc;
 }
 return pAssoc->value;  // return new reference
}

CMapPtrToPtr::CAssoc* CMapPtrToPtr::NewAssoc()
{
         ......//省略。
 pAssoc->key = 0;

 pAssoc->value = 0;

 return pAssoc;
}
问题1.
     在CArchive::WriteObject中,nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0返回的是一个索引,而(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++; 赋的值是Map的长度(大小),m_pStoreMap是CMapPtrToPtr类,并该类型且重载了“[]”运算符,而从CMapPtrToPtr::operator[]返回的是m_pHashTable的某一项(CAssoc类型)的value值(自己看一下源代码,因为字数有限,不多写)。那么按照我的理解,(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++; 是把m_nMapCount赋值给m_pHashTable的某一项(CAssoc类型)的value,就是说CAssoc.value是存储m_pHashTable的索引的,这是我的理解。
     想问的是,既然上面的代码中nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0 是返回一个索引,那么为什么还判断     if (nObIndex < wBigObjectTag)   呢,不是m_nMapCount的长度一定不会大于wBigObjectTag(0x7FFF)吗??

问题2.
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;  是不是想把m_pStoreMap长度赋值给m_pStoreMap某一项的CAssoc.value啊,为什么呢?
问题3.
wBigObjectTag、wNullTag、wNewClassTag、wClassTag等,这些是什么东西,具体有什么作用,我想清楚点...??
问题4.
怎么确定什么时候用wBigObjectTag,什么时候用wNewClassTag等...他们靠什么作为依据呢??还有可以详细解析一下CArchive::WriteObject 和CArchive::WriteClass的源代码??

先谢谢高手......
为了方便你理解,我把你的问题次序调整一下。

问题2:
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
如果执行到这一步,说明m_pStoreMap里没有包含pOb。这句的目的是为了把pOb加入到map里,m_nMapCount其实就是该新加入的pOb的索引值。你仔细想想看。
如果同一个object被保存两次,也就是说对同一个pObj,调用了两次CArchive::WriteObject(pObj),那么第一次,pObj->Serialize()会被调用,但是第二次,只需要保存它的索引值就够了。这样其实也起到压缩的作用。
就比如说,你要保存两本一样的书,保存第一本的时候,花了好大篇幅抄了一遍手很酸哦,保存第二本的时候,你就不用重新抄一遍了,你只需要写下“跟第一本书一样”就可以了。

然后回到问题1:

m_nMapCount当然有可能大于0x7FFF。你从哪里看到m_nMapCount一定小于0x7FFF?m_nMapCount是一个DWORD值,四字节的哦,它最大可能是nMaxMapCount    ((DWORD)0x3FFFFFFE) 。
比如nObIndex是0x1000,那么保存的就是0x1000两个字节。如果nObIndex是0x10000000,那么保存的就是0x7FFF 0x1000 0000六个字节。0x7FFF起的作用其实类似于通配符,明白了不?

因为大部分情况下,nObIndex的值都会小于0x7FFF(3万多个object足够应付大部分应用了吧),所以大部分情况下,只需要2个字节就够了。你想想看,如果不采用这种方式,而改为直接保存nObIndex,那么所有情况下都需要4个字节。所以这么做其实是为了压缩数据。

问题3:
wBigObjectTag、wNullTag、wNewClassTag、wClassTag
这些其实都是标志符。。源码注释里有说明的。。我给你翻译成中文好了
#define wNullTag        ((WORD)0)           // special tag indicating NULL ptrs
表示保存了一个空指针。

#define wNewClassTag    ((WORD)0xFFFF)      // special tag indicating new CRuntimeClass
表示这是一个新的runtime class。如果不理解什么是runtime class,建议去学习下MFC的RTTI。。就不详细解释了

#define wClassTag       ((WORD)0x8000)      // 0x8000 indicates class tag (OR'd)
表示这个对象是一个runtime class,但是不是新的。

#define dwBigClassTag   ((DWORD)0x80000000) // 0x8000000 indicates big class tag (OR'd)
作用类似于wBigObjectTag,前面我给你讲了对吧

#define wBigObjectTag   ((WORD)0x7FFF)      // 0x7FFF indicates DWORD object tag
前面我讲了

#define nMaxMapCount    ((DWORD)0x3FFFFFFE) // 0x3FFFFFFE last valid mapCount
CMap的最大容量

问题4:
那些tag用途前面我解释了,它们都是给CArchive用的。你可以这么理解,这些tag其实描述了MFC的序列化"协议"。但是这个协议是私有的,其实你真没什么必要去学习它,因为这东西太简单没什么值得学习的。。值得学习的是CArchive怎么结合RTTI来保存对象的思想。

0分的问题哦,没想到已经打了这么字,划不来啊。。。
详细解释源码嘛,这个我真的不想干了。。其实之前也没看过这些代码,就是为了你这个问题我才找到这个文件读了下的。微软的代码质量的确可以,可读性很高,真的不难看懂。你别把这玩意想的太神秘,自己看看想想就知道了。没必要钻牛角尖,读懂设计思想就可以了。太细节的地方其实没有什么学习的价值,比如为什么dwBigClassTag是0x80000000,因为这个值够大呗,其实定义成0x40000000也不会错(如果没跟其他值冲突的话)
 
   
 
   
可以参考http://news.dayoo.com/tech/201005/21/10000617_102079220.htm
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值