Red de conocimiento informático - Computadora portátil - Pasos para DECLARE_SERIAL

Pasos para DECLARE_SERIAL

Es sorprendente cómo ar determina qué clase debe crearse en función del archivo (énfasis en el archivo, no en codificación), ¿no es así?

Hay varios pasos:

1. Dado que DECLARE_SERIAL sobrecarga el operador >>, se garantiza que llamará a la función >> de la clase CMessg.

2. >>La función en realidad llama a la función ReadObject(CRuntimeClass*) de ar

3. ReadObject primero lee la información de juicio de clase (tal vez una cadena, también puede ser un índice de clase). ), y luego obtenga el nombre de clase de la clase correspondiente

4./ Hay una lista de todas las RuntimeClasses en el estado del módulo del programa, por lo que necesita encontrar el soporte para RuntimeClass; mediante el programa correspondiente (en comparación con ClassName), se obtiene la RuntimeClass correspondiente;

5.RuntimeClass contiene un método para crear objetos, CreateObject, al que se puede llamar para crear el objeto correspondiente. Aquí, dado que CreateObject es en realidad un objeto New, similar a new CMessg, para admitir la serialización, se debe utilizar el constructor sin parámetros;

6. Después de crear el objeto, llame a Seralize(ar) para leer la información del objeto real.

7. Devuelve el puntero del objeto.

8. pMessg apuntará al objeto correspondiente. Seis tecnologías clave para la simulación MFC

Las macros DECLARE_SERIAL / IMPLEMENT_SERIAL deberían sobrecargar los operadores << y >>, y colocar la función Serialize discretamente en la declaración de clase

y, finalmente, un buen enfoque. Todavía es usar macros.

El requisito previo para que una clase pueda leer y escribir archivos es que tenga la capacidad de generarse dinámicamente, por lo que MFC diseñó dos macros

DECLARE_SERIAL e IMPLEMENT_SERIAL:

#define DECLARE_SERIAL (nombre_clase)\

DECLARE_DYNCREATE(nombre_clase)\

operador amigo de CArchive& AFXAPI>> (CArchive& ar, nombre_clase* &pOb);

# define IMPLEMENT_SERIAL( nombre_clase, nombre_clase_base, wSchema)\

CObject* PASCAL nombre_clase::CreateObject() \

{ devuelve nuevo nombre_clase }\

_IMPLEMENT_RUNTIMECLASS(nombre_clase, nombre_clase_base, wSchema, \

nombre_clase::CreateObject) \

Operador CArchive&.AFXAPI>>(CArchive& ar, nombre_clase* &pOb) \

{ pOb = (class_name*) ar.ReadObject(RUNTIME_CLASS(class_name)); \

return ar }

Para poder procesar algunos antes de procesar (lectura) o escritura) cada objeto Para obtener detalles, como determinar si es la primera vez

aparece, número de versión de grabación, nombre del archivo de grabación, etc., CRuntimeClass requiere dos funciones: carga y almacenamiento

struct CRuntimeClass

{

// Atributos

LPCSTR m_lpszClassName;

int m_nObjectSize;

UINT m_wSchema; // Número de esquema de clases cargadas

UINT m_wSchema; // Número de esquema de clase cargada

Objeto* (PASCAL* m_pfnCreateObject)( // NULL => Clase abstracta

CRuntimeClass* m_pBaseClass;

CObject * CreateObject();

void Store(CArchive& ar)

estático CRuntimeClass* PASCAL; Load(CArchive& ar, UINT* pwSchemaNum);

// Los objetos CRuntimeClass están vinculados entre sí en una lista simple

static CRuntimeClass* pFirstClass // Inicio de la lista de clases

CRuntimeClass* m_pNextClass; // Lista vinculada de clases registradas

};

Ya has visto la función de carga en la sección anterior. Para simplificar, eliminé sus parámetros y. los reemplazó con el nombre de la clase en la pantalla

, cuando en realidad debería leer el nombre de la clase del archivo. De hecho, debería leer los nombres de las categorías del archivo.

En cuanto a la función Store, escribe el nombre de la categoría en el archivo:

// Código de serialización de la clase Runtime

CRuntimeClass* PASCAL CRuntimeClass::Load(CArchive& ar, UINT* pwSchema) .

{

WORD nLen;

char szClassName[64];

CRuntimeClass* pClass;

ar >> (WORD&)(* pwSchemaNum) >> nLen;

if (nLen >= sizeof(szClassName) || ar.Read(szClassName, nLen) != nLen)

Devuelve NULL;

szClassName[nLen] = ~\0~;

for (pClass = pFirstClass; pClass != NULL; pClass = pClass->m_pNextClass)

{

if (lstrcmp(szClassName, pClass->m_lpszClassName) == 0)

return pClass;

}

return NULL; // no encontrado

}

void CRuntimeClass: Write(m_l lpszClassName, nLen*sizeof(char));

}

clase CScribDoc: CDocumento público

{

DECLARE_DYNCREATE(CScribDoc)

...

};

clase CStroke: CObject público

{

DECLARE_SERIAL(CStroke)

público:

void Serialize(CArchive&);.

...

};

clase CRectangle: objeto CO público

{

DECLARE_SERIAL(CRectangle)

público:

void Serialize(CArchive&);

Void Serialize(CArchive&);

... amp;);

...

};

clase CCircle: CObject público

{

DECLARE_SERIAL(CCircle)

p>público:

void Serialize(CArchive& amp;...

...

};

Y haga lo siguiente en el archivo .CPP:

IMPLEMENT_DYNCREATE(CScribDoc, CDocument)

IMPLEMENT_SERIAL(CStroke, CObject, 2)

IMPLEMENT_SERIAL(CRectangle, CObject, 1)

IMPLEMENT_SERIAL(CCircle, CObject, 1)

¿Y luego qué? Analicemos las funciones de serialización de CStroke, CRectangle y CCircle.

Por supuesto, no sorprende que el código fuente MFC de CObList y CDWordArray sea así:

// En el archivo de encabezado

clase CDWordArray : CObject público

{

DECLARE_SERIAL(CDWordArray)

público:

void Serialize(CArchive&);

...

};

clase CObList: CObject público

{

DECLARE_SERIAL(CObList)

public:

void Serialize(CArchive&);...

...

};

// En el archivo de implementación

IMPLEMENT_SERIAL(CObList, CObject, 0)

IMPLEMENT_SERIAL(CDWordArray, CObject, 0)

Y CObject tiene una función virtual adicional Serializar:

clase CObject

{

público:

virtual void Serialize(CArchive& ar);

...

}