Программирование на языке MFC

Мой второй блог в серии программирования

Метод ReadClass


После того, что мы узнали о записи объекта в архив, мы можем догадаться, что первым делом метод ReadObject() постарается считать данные о классе объекта. Как видно из текста метод, так оно и происходит. Для считывания информации о классе использу­ется метод ReadClass(). Исходный код этого метода находится в файле afxobj.cpp:

CRuntimeClass* CArchive::ReadClass(const

CRuntimeClass* pClassRefRequested, UINT* pSchema, DWORD* pObTag)

{

ASSERT(pClassRefRequested == NULL || AfxIsValidAddress(pClassRefRequested,

sizeof(CRuntimeClass), FALSE));

ASSERT(IsLoading()); // proper direction

if (pClassRefRequested != NULL &&

pClassRefRequested->m_wSchema == OxFFFF)

{

TRACE1("Warning: Cannot call ReadClass/ReadObject

for %hs.\n", pClassRefRequested->m_lpszClassName); AfxThrowNotSupportedException ();

}

// make sure m_pLoadArray is initialized MapObject(NULL);

// read object tag – if prefixed by wBigObjectTag // then DWORD tag follows

DWORD obTag;

WORD wTag;

*this >> wTag;

if (wTag == wBigObjectTag) *this » obTag;

else

obTag = ( (wTag & wClassTag) « 16) | (wTag & -wClassTag);

// check for object tag (throw exception if // expecting class* tag)

if (!(obTag & dwBigClassTag)) {

if (pObTag == NULL)

AfxThrowArchiveException(CArchiveException::badlndex,

m_strFileName);

*pObTag = obTag; return NULL;

CRuntimeClass* pClassRef;

UINT nSchema;

if (wTag == wNewClassTag)

{

// new object follows a new class id

if ((pClassRef = CRuntimeClass::Load(*this,

&nЈchema)) == NULL) AfxThrowArchiveException(CArchiveException::badClass,

m_strFileName);

// check nSchema against the expected schema if ((pClassRef->m_wSchema &

~VERSIONABLE_SCHEMA) != nSchema)

{

if (! (pClassRef->m_wSchema & VERSIONABLE_SCHEMA) ) {

// schema doesn’t match and not marked as VERSIONABLE_SCHEMA Af xThrowArchiveException (CArchiveException: :badSchema,

m_strFileName);

}

else {

// they differ — store the schema for later retrieval if (m_pSchemaMap == NULL)

m_pSchemaMap = new CMapPtrToPtr; ASSERT_VALID(m_pSchemaMap);

m_pSchemaMap->SetAt(pClassRef, (void*)nSchema) ;

}

}

CheckCount ();

m_pLoadArray->InsertAt(m_nMapCount++, pClassRef) ;

}

else {

// existing class index in obTag followed by new object DWORD nClassIndex = (obTag & -dwBigClassTag); if (nClassIndex == 0 I I

nClassIndex > (DWORD)m_pLoadArray->GetUpperBound() ) AfxThrowArchiveException(CArchiveException::badlndex,

m_strFileName);

pClassRef =

(CRuntimeClass*)m_pLoadArray->GetAt(nClassIndex); ASSERT(pClassRef !=NULL);

// determine schema stored against objects of this type void* pTemp; BOOL bFound = FALSE; nSchema = 0;

if (m_pSchemaMap != NULL) {

bFound = m_pSchemaMap->Lookup( pClassRef, pTemp ); if (bFound)

nSchema = (UINT)pTemp;

}

if (!bFound)

nSchema = pClassRef->m_wSchema & ~VERSIONABLE_SCHEMA;

}

// check for correct derivation if (pClassRefRequested != NULL &&

!pClassRef->IsDerivedFrom(pClassRefRequested))

{

AfxThrowArchiveException(CArchiveException::badClass,

m_strFileName);

}

// store nSchema for later examination if (pSchema != NULL)

*pSchema = nSchema; else

m_nObjectSchema = nSchema;

// store obTag for later examination if (pObTag != NULL) *pObTag = obTa^;

// return the resulting CRuntimeClass* return pClassRef;

}

В качестве аргументов методу передается указатель на ин­формацию времени выполнения класса, а также ссылки на два поля, которые будут заполнены значениями, считанными из ар­хива. В поле pSchema будет записана схема (версия) класса, а в поле obTag будет записан тэг объекта, каким он был записан в архив. Смысл передачи ссылки на схему и на тэг объекта понятен. А зачем мы передаем указатель на информацию вре­мени выполнения класса? Дело обстоит очень просто. Вполне вероятно, что наша программа уже изменилась и чо в нашей программе класс, который мы готовимся считать из архива, просто не описан, верно? Или, скажем, мы по ошибке открыли архив, созданный другой программой, или… Да мало ли что может приключиться! Мы должны убедиться в том, что мы считываем из архива объект именно того класса, о котором у нас есть информация, верно?

Похожие статьи: