Serialização: criando uma classe serializável

Cinco etapas principais são necessárias para tornar uma classe serializável. Elas são apresentadas abaixo e explicadas nas seguintes seções:

  1. Como derivar sua classe de CObject (ou de alguma classe derivada).CObject

  2. Como substituir a função membro Serialize.

  3. Como usar a macro DECLARE_SERIAL na declaração de classe.

  4. Como definir um construtor que não aceita argumentos.

  5. Como usar a macro IMPLEMENT_SERIAL no arquivo de implementação para sua classe.

Se você chamar Serialize diretamente e não por meio dos operadores >> e << do CArchive, as últimas três etapas não serão necessárias para serialização.

Como derivar uma classe de CObject

O protocolo de serialização básico e a funcionalidade são definidos na classe CObject. Ao derivar sua classe de CObject (ou de uma classe derivada de CObject), conforme mostrado na declaração de classe CPerson a seguir, você obtém acesso ao protocolo de serialização e à funcionalidade de CObject.

Como substituir a função de membro serializar

A função de membro Serialize, que é definida na classe CObject, é responsável por realmente serializar os dados necessários para capturar o estado atual de um objeto. A função Serialize tem um argumento CArchive que ela usa para ler e gravar os dados do objeto. O objeto CArchive tem uma função de membro, IsStoringque indica se Serialize está armazenando (gravando dados) ou carregando (lendo dados). Usando os resultados de IsStoring como guia, insira os dados do objeto no objeto CArchive com o operador de inserção (<<) ou extraia dados com o operador de extração (>>).

Considere uma classe derivada de CObject e que tenha duas novas variáveis de membro, de tipos CString e WORD. O seguinte fragmento de declaração de classe mostra as novas variáveis de membro e a declaração para a função de membro substituída Serialize:

class CPerson : public CObject
{
public:
   DECLARE_SERIAL(CPerson)
   // empty constructor is necessary
   CPerson();
   virtual ~CPerson();

   CString m_name;
   WORD   m_number;

   void Serialize(CArchive& archive);
};

Para substituir a função membro Serialize

  1. Chame sua versão da classe base Serialize para garantir que a parte herdada do objeto seja serializada.

  2. Insira ou extraia as variáveis de membro específicas para sua classe.

    Os operadores de inserção e extração interagem com a classe de arquivo morto para ler e gravar os dados. O seguinte exemplo mostra como implementar Serialize para a classe CPerson declarada acima:

    void CPerson::Serialize(CArchive& archive)
    {
       // call base class function first
       // base class is CObject in this case
       CObject::Serialize(archive);
    
       // now do the stuff for our specific class
       if (archive.IsStoring())
          archive << m_name << m_number;
       else
          archive >> m_name >> m_number;
    }
    

Você também pode usar as funções de membro CArchive::Read e CArchive::Write para ler e gravar grandes quantidades de dados não tipados.

Como usar a macro DECLARE_SERIAL

A macro DECLARE_SERIAL é necessária na declaração de classes que darão suporte à serialização, conforme mostrado aqui:

class CPerson : public CObject
{
public:
   DECLARE_SERIAL(CPerson)

Como definir um construtor sem argumentos

O MFC requer um construtor padrão quando ele recria seus objetos à medida que eles são desserializados (carregados do disco). O processo de desserialização preencherá todas as variáveis de membro com os valores necessários para recriar o objeto.

Esse construtor pode ser declarado público, protegido ou privado. Se você torná-lo protegido ou privado, ajudará a garantir que ele só será usado pelas funções de serialização. O construtor deve colocar o objeto em um estado que permita que ele seja excluído, se necessário.

Observação

Se você esquecer de definir um construtor sem argumentos em uma classe que usa as macros DECLARE_SERIAL e IMPLEMENT_SERIAL, receberá um aviso do compilador "sem construtor padrão disponível" na linha em que a macro IMPLEMENT_SERIAL é usada.

Como usar a macro IMPLEMENT_SERIAL no arquivo de implementação

A macro IMPLEMENT_SERIAL é usada para definir as várias funções necessárias quando você deriva uma classe serializável de CObject. Você usa essa macro no arquivo de implementação (.CPP) para sua classe. Os dois primeiros argumentos para a macro são o nome da classe e o nome de sua classe base imediata.

O terceiro argumento para essa macro é um número de esquema. O número do esquema é essencialmente um número de versão para objetos da classe. Use um inteiro maior ou igual a 0 para o número de esquema. (Não confunda esse número de esquema com a terminologia do banco de dados.)

O código de serialização MFC verifica o número do esquema ao ler objetos na memória. Se o número de esquema do objeto no disco não corresponder ao número de esquema da classe na memória, a biblioteca gerará um CArchiveException, impedindo que seu programa leia uma versão incorreta do objeto.

Se você quiser que sua função de membro Serialize possa ler várias versões, ou seja, arquivos gravados com versões diferentes do aplicativo, poderá usar o valor VERSIONABLE_SCHEMA como um argumento para a macro IMPLEMENT_SERIAL. Para informações de uso e um exemplo, confira a função de membro GetObjectSchema da classe CArchive.

O seguinte exemplo mostra como usar IMPLEMENT_SERIAL para uma classe, CPerson, que é derivada de CObject:

IMPLEMENT_SERIAL(CPerson, CObject, 1)

Depois de ter uma classe serializável, você pode serializar objetos da classe, conforme discutido no artigo Serialização: como serializar um objeto.

Confira também

Serialização