C++ C++ C# C# ASP.NET Security ASP.NET Security ASM ASM Скачать Скачать Поиск Поиск Хостинг Хостинг  
  Программа для работы с LPT портом...
Язык: .NET — ©Alexey...
  "ASP.NET Atlas" – AJAX в исполнении Micro...
Язык: .NET — ©legigor@mail.ru...
  "Невытесняющая" Многопоточность...
Язык: C/C++ — ©...
  01.05.2010 — Update World C++: Сборник GPL QT исходников
  15.12.2007 — Весь сайт целиком можно загрузить по ссылкам из раздела Скачать
Хостинг:
Windows 2003, ASP.NET 2.0
бесплатный и от 80 руб./мес


   Отправить письмо
Кулабухов Артем, Беларусь




 Урок 29. Сериализация в классе / Уроки C++ .NET / Visual C++ .NET

Visual C++.NET
Урок 29. Сериализация в классе

Рассмотрим такую задачу - вы создали приложение с использованием архитектуры Документ-Вид. При этом ваши данные организованы весьма сложно - это значит, что для них надо создавать собственный класс. В классе документа вы объявляете экземпляр этого класса - и тут встает вопрос о том, как данные этого класса читать и записывать из и в файл. Проблема состоит еще в том, что записывать из вашего класса в файл вы хотите не все данные, а только те, которые нужно.

Как вы знаете, для этого служит метод Serialize класса документа. В нем, конечно, можно написать что-то вроде:

// CtestmfcDoc serialization
void CtestmfcDoc::Serialize(CArchive& ar)
{
  if (ar.IsStoring())
  {
    // TODO: add storing code here
    ar<<m_Data.m_nAge;
    ar<<m_Data.m_sName;

  }
  else
  {
    // TODO: add loading code here
    ar>>m_Data.m_nAge;
    ar>>m_Data.m_sName;
  }
}

Тут мы предполагаем, что переменная m_Data имеет тип нашего класса для данных и в ней есть 2 открытые переменные с данными - m_nAge и m_sName.

Но приведенное решение не слишком хорошее: так как что именно из нашего класса данных сериализовать, мы определяем в другом классе - а именно в классе документа. Если мы потом добавим еще некоторые данные для сериализации в классе данных, то внести соответствующие строки в метод Serialize класса документа мы можем и забыть.

Поэтому сейчас мы рассмотрим, как поставленную задачу решать правильно. А именно, наш класс данных CData сам будет определять, что в нем надо сериализовывать. Тогда, как вы увидите, и метод Serialize для класса документа будет выглядеть совсем просто.

Итак, создайте с помощью мастера SDI-приложение с поддержкой архитектуры Документ-Вид. Все параметры можно оставить без изменения. Пусть для определенности наш проект называется testmfc.

Добавьте в проект класс для данных CData. Ниже приводятся текст заголовочного файла и файла реализации для этого класса.

Заголовочный файл:

#pragma once
#include "afx.h"
//Наш класс должен быть потомком класса CObject.
class CData :
  public CObject
{
public:
  //Объявляем метод для сериализации класса.
  void Serialize(CArchive& ar);
  CData(void);
  ~CData(void);
  CString m_sName;
  //Данные класса.
  int m_nAge;
  int m_nSomeData;
  //Необходимый для сериализации макрос.
  DECLARE_SERIAL(CData)
};

Файл реализации:

#include "StdAfx.h"
#include "data.h"
//Необходимый для сериализации макрос.
IMPLEMENT_SERIAL(CData, CObject, VERSIONABLE_SCHEMA | 1)
CData::CData(void)
{
}
CData::~CData(void)
{
}
//Наша реализация сериализации.
//Сериализуем только нужные нам данные.
void CData::Serialize(CArchive& ar)
{
  if (ar.IsStoring())
    {
      // TODO: add storing code here
      ar<<m_nAge;
      ar<<m_sName;
    }
    else
    {
      // TODO: add loading code here
      ar>>m_nAge;
      ar>>m_sName;
    }
}

Немного комментария по коду. Для того, чтобы наш класс стал сериализуемым, мы должны сделать четыре действия:

Во-перых, объявить наш класс потомком класса CObject.

Во-вторых, в заголовочный файл класса вставить макрос DECLARE_SERIAL(...). Его единственный параметр - это имя нашего класса.

В-третьих, в файл реализации вставить макрос IMPLEMENT_SERIAL(CData, CObject, VERSIONABLE_SCHEMA | 1). Его первый параметр - это имя нашего класса, второй - имя его предка, а третий параметр нужен для того, чтобы можно было работать с разными вариантами сериализации (это, например, может оказаться полезным при работе со старыми версиями файлов).

В-четвертых, в классе надо написать свой вариант метода Serialize(CArchive& ar). Этот метод есть в классе CObject и мы должны его переопределить. Так вот, как раз в реализации этого метода мы и должны написать, что наш класс должен сохранять в файле, а что не должен. Обратите внимание, что в нашей реализации мы записываем и читаем только те переменные класса, которые хотим сохранять (m_nAge и m_sName).

С классом CData все. Теперь посмотрим, как этот класс будет работать в нашей программе. Добавьте экземпляр класса в класс документа:

class CtestmfcDoc : public CDocument
{
  ...
public:
  // Данные.
  CData m_Data;
};

В методе OnNewDocument задайте начальные значения для наших данных:

BOOL CtestmfcDoc::OnNewDocument()
{
  ...
  m_Data.m_nAge=23;
  m_Data.m_nSomeData=55;
  m_Data.m_sName="Irina";
  return TRUE;
}

В классе вида напишите код для изменения и отображения данных класса документа:

void CtestmfcView::OnLButtonDown(UINT nFlags, CPoint point)
{
  // TODO: Add your message handler code here and/or call default
  CtestmfcDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);
  //Изменяем данные.
  pDoc->m_Data.m_nAge++;
  pDoc->m_Data.m_nSomeData++;
  pDoc->m_Data.m_sName="Igor";
  Invalidate();
  CView::OnLButtonDown(nFlags, point);
}
void CtestmfcView::OnDraw(CDC* pDC)
{
  CtestmfcDoc* pDoc = GetDocument();
  ASSERT_VALID(pDoc);
  // TODO: add draw code for native data here
  //Выводим данные.
  CString s;
  s.Format("%d", pDoc->m_Data.m_nAge);
  pDC->TextOut(10, 10, s);
  s.Format("%d", pDoc->m_Data.m_nSomeData);
  pDC->TextOut(10, 30, s);
  pDC->TextOut(10, 50, pDoc->m_Data.m_sName);
}

И, наконец, самое главное. Реализация метода Serialize в классе документа (сравните с реализацией в начале урока):

void CtestmfcDoc::Serialize(CArchive& ar)
{
  //Сериализация данных.
  m_Data.Serialize(ar);
  if (ar.IsStoring())
  {
    ...
}

Как вы видите, вся сериализация свелась к одной строке.

Компилируйте и запускайте программу. Сначала при запуске программа покажет данные 23, 55 и Irina:

Данные при запуске.

Если щелкнуть в окне мышкой, то данные изменятся на 24, 56 и Igor:

Данные после изменения.

Сохранияем документ, закрываем программу, потом снова запускаем и открываем сохраненный документ. При этом покажутся данные 24, 55 и Igor:

Данные после сохранения.

Обратите внимание, что сохранились только данные, задаваемые переменными m_nAge и m_sName (24 и Igor) класса CData, а данные, относящиеся к переменной m_nSomeData (56), не сохранились. Это потому, что мы так сделали в методе Serialize класса CData.