程序调试--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))
- {
-
- AfxThrowArchiveException(CArchiveException::badClass, m_strFileName);
- }
- }
- else
- {
- TRY
- {
-
- pOb = pClassRef->CreateObject();
- if (pOb == NULL)
- AfxThrowMemoryException();
-
- CheckCount();
- m_pLoadArray->InsertAt(m_nMapCount++, pOb);
-
- UINT nSchemaSave = m_nObjectSchema;
- m_nObjectSchema = nSchema;
- pOb->Serialize(*this);
- m_nObjectSchema = nSchemaSave;
- }
- CATCH_ALL(e)
- {
- if(pOb!=NULL)
- {
- delete pOb;
- pOb=NULL;
- }
- THROW_LAST();
- }
- END_CATCH_ALL
- }
- return pOb;
- }
函数首先调用CArchive::ReadClass()函数,从数据中读取出类的CRuntimeClass信息,并返回对应的CRuntimeClass指针。
-
- #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)
- {
- TRACE(traceAppMsg, 0, "Warning: Cannot call ReadClass/ReadObject for %hs./n",
- pClassRefRequested->m_lpszClassName);
- AfxThrowNotSupportedException();
- }
-
- MapObject(NULL);
-
- DWORD obTag;
- WORD wTag;
- *this >> wTag;
- if (wTag == wBigObjectTag)
- *this >> obTag;
- else
- obTag = ((wTag & wClassTag) << 16) | (wTag & ~wClassTag);
-
- if (!(obTag & dwBigClassTag))
- {
- if (pObTag == NULL)
- AfxThrowArchiveException(CArchiveException::badIndex, m_strFileName);
- *pObTag = obTag;
- return NULL;
- }
- CRuntimeClass* pClassRef;
- UINT nSchema;
- if (wTag == wNewClassTag)
- {
-
- 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))
- {
-
- 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);
-
- 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;
-
- 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)
-
- {
- 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* pClass = FromName(szClassName);
- if (pClass == NULL)
- {
-
- TRACE(traceAppMsg, 0, "Warning: Cannot load %hs from archive. Class not defined./n",
- szClassName);
- }
- return pClass;
- }