程序调试--CObject对象的串行化

程序调试--CObject对象的串行化


程序代码

  1. #include <afxwin.h>  
  2. class CMyClass : public CObject  
  3. {  
  4.     DECLARE_SERIAL(CMyClass)  
  5. public:  
  6.     CMyClass(int n = 10) : m_nData(n) {}  
  7.     virtual void Serialize(CArchive& ar);  
  8. protected:  
  9.     int m_nData;  
  10. };  
  11. IMPLEMENT_SERIAL(CMyClass, CObject, 1)  
  12. void CMyClass::Serialize(CArchive& ar)  
  13. {  
  14.     CObject::Serialize(ar);  
  15.     if (ar.IsStoring())  
  16.         ar<<m_nData;  
  17.     else  
  18.         ar>>m_nData;  
  19. }  
  20. int _tmain(int argc, _TCHAR* argv[])  
  21. {  
  22.     CFile file("file.dat", CFile::modeRead);  
  23.     CArchive ar(&file, CArchive::load);  
  24.       
  25.     CMyClass *pMyClass1, *pMyClass2;  
  26.     ar>>pMyClass1>>pMyClass2;  
  27.     return 0;  
  28. }  
 

 

在序列化宏IMPLEMENT_SERIAL中定义了一个重载>>的运算符,宏展开如下:

  1. CArchive& operator>>(CArchive& ar, CMyClass* &pOb)       
  2. {  
  3.     pOb = (CMyClass*)ar.ReadObject(RUNTIME_CLASS(CMyClass));      
  4.     return ar;  
  5. }  
 

传进去指针的引用,然后>>运算符将根据文件中类的数据构建对象,将对象指针赋给pOb。它通过调用CArchive::ReadObject()函数,来构建出对象并做相应的初始化。

 

  1. CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)  
  2. {  
  3.     if (!IsLoading())   
  4.     {  
  5.         AfxThrowArchiveException(CArchiveException::writeOnly, m_strFileName);  
  6.     }  
  7.     // 从文件中先读取对象类信息  
  8.     UINT nSchema;  
  9.     DWORD obTag;  
  10.     CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag);  
  11.     // 查看是否已经加载过该对象  
  12.     CObject* pOb=NULL;  
  13.     if (pClassRef == NULL)      // 表明之前已经加载过该对象  
  14.     {  
  15.         if (obTag > (DWORD)m_pLoadArray->GetUpperBound())  
  16.         {  
  17.             // 返回的对象标识不合法  
  18.             AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);  
  19.         }  
  20.         pOb = (CObject*)m_pLoadArray->GetAt(obTag);  
  21.         if (pOb != NULL && pClassRefRequested != NULL &&  
  22.             !pOb->IsKindOf(pClassRefRequested))  
  23.         {  
  24.             // 加载了一个对象但是并非指定继承自pClassRefRequested.  
  25.             AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);  
  26.         }  
  27.     }  
  28.     else  
  29.     {  
  30.         TRY  
  31.         {  
  32.             // 动态创建  
  33.             pOb = pClassRef->CreateObject();  
  34.             if (pOb == NULL)  
  35.                 AfxThrowMemoryException();  
  36.             // Add to mapping array BEFORE de-serializing  
  37.             CheckCount();  
  38.             m_pLoadArray->InsertAt(m_nMapCount++, pOb);  
  39.             // 从文件中并行化对象数据  
  40.             UINT nSchemaSave = m_nObjectSchema;  
  41.             m_nObjectSchema = nSchema;      // 待序列化类的版本号  
  42.             pOb->Serialize(*this);  
  43.             m_nObjectSchema = nSchemaSave;      // 原CArchive中存储的版本号  
  44.         }  
  45.         CATCH_ALL(e)  
  46.         {  
  47.             if(pOb!=NULL)  
  48.             {  
  49.                 delete pOb;  
  50.                 pOb=NULL;  
  51.             }  
  52.             THROW_LAST();  
  53.         }  
  54.         END_CATCH_ALL  
  55.     }  
  56.     return pOb;  
  57. }  

函数首先调用CArchive::ReadClass()函数,从数据中读取出类的CRuntimeClass信息,并返回对应的CRuntimeClass指针。

 

  1. // Pointer mapping constants  
  2. #define wNullTag        ((WORD)0)           // special tag indicating NULL ptrs  
  3. #define wNewClassTag    ((WORD)0xFFFF)      // special tag indicating new CRuntimeClass  
  4. #define wClassTag       ((WORD)0x8000)      // 0x8000 indicates class tag (OR'd)  
  5. #define dwBigClassTag   ((DWORD)0x80000000) // 0x8000000 indicates big class tag (OR'd)  
  6. #define wBigObjectTag   ((WORD)0x7FFF)      // 0x7FFF indicates DWORD object tag  
  7. #define nMaxMapCount    ((DWORD)0x3FFFFFFE) // 0x3FFFFFFE last valid mapCount  
  8.   
  9. CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested,  
  10.                                    UINT* pSchema, DWORD* pObTag)  
  11. {  
  12.     if (!IsLoading())   
  13.     {  
  14.         AfxThrowArchiveException(CArchiveException::genericException, m_strFileName);  
  15.     }  
  16.     if (pClassRefRequested != NULL && pClassRefRequested->m_wSchema == 0xFFFF)  
  17.     {       // 确保待读取类的版本号不为0xFFFF  
  18.         TRACE(traceAppMsg, 0, "Warning: Cannot call ReadClass/ReadObject for %hs./n",  
  19.             pClassRefRequested->m_lpszClassName);  
  20.         AfxThrowNotSupportedException();  
  21.     }  
  22.     // make sure m_pLoadArray is initialized  
  23.     MapObject(NULL);  
  24.     // 读取对象标记  
  25.     DWORD obTag;  
  26.     WORD wTag;  
  27.     *this >> wTag;  
  28.     if (wTag == wBigObjectTag)        
  29.         *this >> obTag;       // 大标记,说明接下来的4字节数据才是对象标识  
  30.     else  
  31.         obTag = ((wTag & wClassTag) << 16) | (wTag & ~wClassTag);  
  32.     // 如果表达式为真,则obTag中存储的是对象标识,而非类标识  
  33.     if (!(obTag & dwBigClassTag))  
  34.     {     
  35.         if (pObTag == NULL)  
  36.             AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);  
  37.         *pObTag = obTag;  
  38.         return NULL;        // 返回NULL说明以前已经读取过一个相同的对象,其标识为obTag  
  39.     }  
  40.     CRuntimeClass* pClassRef;  
  41.     UINT nSchema;  
  42.     if (wTag == wNewClassTag)       // 新类标记  
  43.     {  
  44.         // 从文档中读取类信息,返回类的CRuntimeClass指针,同时也传回了版本号。  
  45.         if ((pClassRef = CRuntimeClass::Load(*this, &nSchema)) == NULL)  
  46.             AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);  
  47.         // 校验类的版本号是否正确  
  48.         if ((pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA) != nSchema)  
  49.         {  
  50.             if (!(pClassRef->m_wSchema & VERSIONABLE_SCHEMA))  
  51.             {  
  52.                 // 版本号不对,一种可能是新版本程序读取老版本数据,同时也没有加VERSIONABLE_SCHEMA标识  
  53.                 AfxThrowArchiveException(CArchiveException::badSchema, m_strFileName);  
  54.             }  
  55.             else  
  56.             {  
  57.                 // 先存储模式值等待随后再处理  
  58.                 if (m_pSchemaMap == NULL)  
  59.                     m_pSchemaMap = new CMapPtrToPtr;  
  60.                 m_pSchemaMap->SetAt(pClassRef, (void*)(DWORD_PTR)nSchema);  
  61.             }  
  62.         }  
  63.         CheckCount();  
  64.         m_pLoadArray->InsertAt(m_nMapCount++, pClassRef);  
  65.     }  
  66.     else  
  67.     {  
  68.         // 已存在类的不同对象,先获取类标识  
  69.         DWORD nClassIndex = (obTag & ~dwBigClassTag);  
  70.         if (nClassIndex == 0 || nClassIndex > (DWORD)m_pLoadArray->GetUpperBound())  
  71.             AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);  
  72.         // 根据类标识,查找m_pLoadArray中对应标识下的CRuntimeClass指针  
  73.         pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex);  
  74.         // 判断文档中的类版本号  
  75.         void* pTemp;  
  76.         BOOL bFound = FALSE;  
  77.         nSchema = 0;  
  78.         if (m_pSchemaMap != NULL)  
  79.         {  
  80.             bFound = m_pSchemaMap->Lookup( pClassRef, pTemp );  
  81.             if (bFound)  
  82.                 nSchema = (UINT)(UINT_PTR)pTemp;  
  83.         }  
  84.         if (!bFound)  
  85.             nSchema = pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA;  
  86.     }  
  87.     // 校验继承路径是否正确。  
  88.     if (pClassRefRequested != NULL &&  
  89.         !pClassRef->IsDerivedFrom(pClassRefRequested))  
  90.     {  
  91.         AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);  
  92.     }  
  93.     // 返回版本号  
  94.     if (pSchema != NULL)  
  95.         *pSchema = nSchema;  
  96.     else  
  97.         m_nObjectSchema = nSchema;  
  98.     // 返回对象标识  
  99.     if (pObTag != NULL)  
  100.         *pObTag = obTag;  
  101.     // 返回CRuntimeClass指针  
  102.     return pClassRef;  
  103. }  

第一次写入类对象信息: 0xFFFF 版本号 类名称长度 类名称字符串 对象数据

非第一次同一类不同对象(小标记): (0x8000 | nClassIndex) 对象数据

非第一次同一类不同对象(大标记): 0x7FFF (0x80000000 | nClassIndex) 对象数据

非第一次写入相同对象(小标记): nObIndex

非第一次写入相同对象(大标记): 0x7FFF nObIndex

 

参数意思:

CRuntimeClass* pClassRefRequest 想要读取的CRuntimeClass信息

UINT* pSchema 用于返回读取到的版本号

DWORD* pObTag 用于返回读取到的对象标识

 

CRuntimeClass::Load()函数从文档中读取类信息,返回类的CRuntimeClass指针。

  1. CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum)  
  2. // loads a runtime class description  
  3. {  
  4.     if(pwSchemaNum == NULL)  
  5.     {  
  6.         return NULL;  
  7.     }  
  8.     WORD nLen;  
  9.     char szClassName[64];  
  10.     WORD wTemp;  
  11.     ar >> wTemp; *pwSchemaNum = wTemp;        // 读取版本号  
  12.     ar >> nLen;       // 读取名称类字符串长度  
  13.     // 读取类名称字符串  
  14.     if (nLen >= _countof(szClassName) ||  
  15.         ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char))  
  16.     {  
  17.         return NULL;  
  18.     }  
  19.     szClassName[nLen] = '/0';  
  20.     // 根据指定类名称查找对应的CRuntimeClass指针  
  21.     CRuntimeClass* pClass = FromName(szClassName);  
  22.     if (pClass == NULL)  
  23.     {  
  24.         // not found, trace a warning for diagnostic purposes  
  25.         TRACE(traceAppMsg, 0, "Warning: Cannot load %hs from archive.  Class not defined./n",  
  26.             szClassName);  
  27.     }  
  28.     return pClass;  
  29. }  
 

 

 


你可能感兴趣的:(程序调试--CObject对象的串行化)