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

程序代码

#include <afxwin.h> class CMyClass : public CObject { DECLARE_SERIAL(CMyClass) public: CMyClass(int n = 10) : m_nData(n) {} virtual void Serialize(CArchive& ar); protected: int m_nData; }; IMPLEMENT_SERIAL(CMyClass, CObject, 1) void CMyClass::Serialize(CArchive& ar) { CObject::Serialize(ar); if (ar.IsStoring()) ar<<m_nData; else ar>>m_nData; } int _tmain(int argc, _TCHAR* argv[]) { CFile file("file.dat", CFile::modeRead); CArchive ar(&file, CArchive::load); CMyClass *pMyClass1, *pMyClass2; ar>>pMyClass1>>pMyClass2; return 0; } 

 

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

CArchive& operator>>(CArchive& ar, CMyClass* &pOb) { pOb = (CMyClass*)ar.ReadObject(RUNTIME_CLASS(CMyClass)); return ar; }  

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

 

CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested) { if (!IsLoading()) { AfxThrowArchiveException(CArchiveException::writeOnly, m_strFileName); } // 从文件中先读取对象类信息 UINT nSchema; DWORD obTag; CRuntimeClass* pClassRef = ReadClass(pClassRefRequested, &nSchema, &obTag); // 查看是否已经加载过该对象 CObject* pOb=NULL; if (pClassRef == NULL) // 表明之前已经加载过该对象 { if (obTag > (DWORD)m_pLoadArray->GetUpperBound()) { // 返回的对象标识不合法 AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName); } pOb = (CObject*)m_pLoadArray->GetAt(obTag); if (pOb != NULL && pClassRefRequested != NULL && !pOb->IsKindOf(pClassRefRequested)) { // 加载了一个对象但是并非指定继承自pClassRefRequested. AfxThrowArchiveException(CArchiveException::badClass, m_strFileName); } } else { TRY { // 动态创建 pOb = pClassRef->CreateObject(); if (pOb == NULL) AfxThrowMemoryException(); // Add to mapping array BEFORE de-serializing CheckCount(); m_pLoadArray->InsertAt(m_nMapCount++, pOb); // 从文件中并行化对象数据 UINT nSchemaSave = m_nObjectSchema; m_nObjectSchema = nSchema; // 待序列化类的版本号 pOb->Serialize(*this); m_nObjectSchema = nSchemaSave; // 原CArchive中存储的版本号 } CATCH_ALL(e) { if(pOb!=NULL) { delete pOb; pOb=NULL; } THROW_LAST(); } END_CATCH_ALL } return pOb; }

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

 

// Pointer mapping constants #define wNullTag ((WORD)0) // special tag indicating NULL ptrs #define wNewClassTag ((WORD)0xFFFF) // special tag indicating new CRuntimeClass #define wClassTag ((WORD)0x8000) // 0x8000 indicates class tag (OR'd) #define dwBigClassTag ((DWORD)0x80000000) // 0x8000000 indicates big class tag (OR'd) #define wBigObjectTag ((WORD)0x7FFF) // 0x7FFF indicates DWORD object tag #define nMaxMapCount ((DWORD)0x3FFFFFFE) // 0x3FFFFFFE last valid mapCount CRuntimeClass* CArchive::ReadClass(const CRuntimeClass* pClassRefRequested, UINT* pSchema, DWORD* pObTag) { if (!IsLoading()) { AfxThrowArchiveException(CArchiveException::genericException, m_strFileName); } if (pClassRefRequested != NULL && pClassRefRequested->m_wSchema == 0xFFFF) { // 确保待读取类的版本号不为0xFFFF TRACE(traceAppMsg, 0, "Warning: Cannot call ReadClass/ReadObject for %hs./n", pClassRefRequested->m_lpszClassName); AfxThrowNotSupportedException(); } // make sure m_pLoadArray is initialized MapObject(NULL); // 读取对象标记 DWORD obTag; WORD wTag; *this >> wTag; if (wTag == wBigObjectTag) *this >> obTag; // 大标记,说明接下来的4字节数据才是对象标识 else obTag = ((wTag & wClassTag) << 16) | (wTag & ~wClassTag); // 如果表达式为真,则obTag中存储的是对象标识,而非类标识 if (!(obTag & dwBigClassTag)) { if (pObTag == NULL) AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName); *pObTag = obTag; return NULL; // 返回NULL说明以前已经读取过一个相同的对象,其标识为obTag } CRuntimeClass* pClassRef; UINT nSchema; if (wTag == wNewClassTag) // 新类标记 { // 从文档中读取类信息,返回类的CRuntimeClass指针,同时也传回了版本号。 if ((pClassRef = CRuntimeClass::Load(*this, &nSchema)) == NULL) AfxThrowArchiveException(CArchiveException::badClass, m_strFileName); // 校验类的版本号是否正确 if ((pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA) != nSchema) { if (!(pClassRef->m_wSchema & VERSIONABLE_SCHEMA)) { // 版本号不对,一种可能是新版本程序读取老版本数据,同时也没有加VERSIONABLE_SCHEMA标识 AfxThrowArchiveException(CArchiveException::badSchema, m_strFileName); } else { // 先存储模式值等待随后再处理 if (m_pSchemaMap == NULL) m_pSchemaMap = new CMapPtrToPtr; m_pSchemaMap->SetAt(pClassRef, (void*)(DWORD_PTR)nSchema); } } CheckCount(); m_pLoadArray->InsertAt(m_nMapCount++, pClassRef); } else { // 已存在类的不同对象,先获取类标识 DWORD nClassIndex = (obTag & ~dwBigClassTag); if (nClassIndex == 0 || nClassIndex > (DWORD)m_pLoadArray->GetUpperBound()) AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName); // 根据类标识,查找m_pLoadArray中对应标识下的CRuntimeClass指针 pClassRef = (CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex); // 判断文档中的类版本号 void* pTemp; BOOL bFound = FALSE; nSchema = 0; if (m_pSchemaMap != NULL) { bFound = m_pSchemaMap->Lookup( pClassRef, pTemp ); if (bFound) nSchema = (UINT)(UINT_PTR)pTemp; } if (!bFound) nSchema = pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA; } // 校验继承路径是否正确。 if (pClassRefRequested != NULL && !pClassRef->IsDerivedFrom(pClassRefRequested)) { AfxThrowArchiveException(CArchiveException::badClass, m_strFileName); } // 返回版本号 if (pSchema != NULL) *pSchema = nSchema; else m_nObjectSchema = nSchema; // 返回对象标识 if (pObTag != NULL) *pObTag = obTag; // 返回CRuntimeClass指针 return pClassRef; }

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

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

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

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

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

 

参数意思:

CRuntimeClass* pClassRefRequest 想要读取的CRuntimeClass信息

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

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

 

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

CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchemaNum) // loads a runtime class description { if(pwSchemaNum == NULL) { return NULL; } WORD nLen; char szClassName[64]; WORD wTemp; ar >> wTemp; *pwSchemaNum = wTemp; // 读取版本号 ar >> nLen; // 读取名称类字符串长度 // 读取类名称字符串 if (nLen >= _countof(szClassName) || ar.Read(szClassName, nLen*sizeof(char)) != nLen*sizeof(char)) { return NULL; } szClassName[nLen] = '/0'; // 根据指定类名称查找对应的CRuntimeClass指针 CRuntimeClass* pClass = FromName(szClassName); if (pClass == NULL) { // not found, trace a warning for diagnostic purposes TRACE(traceAppMsg, 0, "Warning: Cannot load %hs from archive. Class not defined./n", szClassName); } return pClass; }  

 

 

 

 

 

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