Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Создание класса, обеспечивающего сериализацию данных




Библиотека классов MFC определяет механизм записи и восстановления объектов (serialization), причем поддержка этого механизма осуществляется средствами класса CObject.

Классы, наследованные от CObject, также могут обеспечивать работу механизма записи и восстановления объектов. Для этого при объявлении класса надо указать макрокоманду DECLARE_SERIAL, а при определении - макрокоманду IMPLEMENT_SERIAL.

Макрокоманду DECLARE_SERIAL необходимо поместить в описании класса в заголовочном файле. В качестве параметра макрокоманды надо указать имя класса

DECLARE_SERIAL (имя_класса)

Макрокоманду IMPLEMENT_SERIAL следует указать перед упоминанием класса в файле исходного текста приложения. Прототип макрокоманды IMPLEMENT_SERIAL представлен ниже:

IMPLEMENT_SERIAL (имя_класса, имя_базового_класса, номер_версии)

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

В классе должны быть определены специальные методы для записи и восстановления состояния объектов этого класса. Обычно эти методы сохраняют и восстанавливают элементы данных из класса. Таким образом, объекты класса сами отвечают за то, как они сохраняют и восстанавливают свое состояние.

Методы, сохраняющие и восстанавливающие объекты, взаимодействуют с объектом класса CArchive, который осуществляет непосредственную запись и чтение информации из файла на диске.

Класс CObject содержит виртуальный метод Serialize, отвечающий за запись и чтение объектов классов, наследованных от класса CObject:

virtual void Serialize(CArchive& ar);

В качестве параметра ar методу передается указатель на объект класса CArchive, используемый для записи и восстановления состояния объекта класса CObject (или наследуемого от него класса). Чтобы узнать, какую операцию должен выполнить метод Serialize, необходимо воспользоваться методами IsLoading или IsStoring класса CArchive.

Итак, при создании нового класса, в котором метод Serialize применяется для сериализации данных, необходимо:

Чтобы класс был производным от класса CObject или его потомков.

При объявлении класса необходимо вставить макрокоманду DECLARE_SERIAL.

Определить в классе функцию Serialize, отвечающую за хранение переменных класса.

Определить в классе конструктор без параметров. Это может быть защищенный конструктор, если он вызывается только для процесса сериализации данных. В конструкторе возможно динамическое создание объектов и инициализация переменных, если это необходимо.

Объявить в классе деструктор, если требуется выполнить специальные действия при разрушении объектов класса, например, освободить память динамически созданных объектов.

При реализации класса в начало файла реализации вставить макрос IMPLEMENT_SERIAL. У этой макрокоманды три параметра: имя класса, имя базового класса и номер версии формата файла, хранящего документ. Можно иметь несколько модификаций документа и с каждой из них связать свою версию.

Шаблон (заготовка) файлов определения и реализации класса, который обеспечивает процесс сериализации данных

// фрагмент файла определения класса

 

 


class CMyDoc:public CObject

{

    DECLARE_SERIAL(CMyDoc)

 

protected:

    virtual void Serialize(CArchive& ar);

 

protected:

    CMyDoc();

 

protected:

    ~CMyDoc();

 

// другие описания класса

. . .

};

 

// фрагмент файла реализации класса

 

IMPLEMENT_SERIAL(CMyDoc, CObject,1)

 

CMyDoc::CMyDoc()

{

    // здесь возможно динамическое создание объектов и

    // инициализация переменных, если это необходимо

    . . .

}

 

CMyDoc::~CMyDoc()

{

    // здесь возможно выполнение специальных действий

    // при разрушении объектов класса, например,

    // освобождение памяти динамически созданных объектов

    . . .

}

 

void CMyDoc::Serialize(CArchive& ar)

{

    if(ar.Storing())

    {

             // здесь следует добавить код для записи переменных в архив

             . . .

    }

    else

    {

             // здесь следует добавить код для чтения переменных из архива,

             . . .

    }

 

    // здесь следует добавить вызовы методов Serialize для переменных

    // класса CMyDoc, являющихся объектами классов,

    // имеющих собственные методы Serialize

    . . .

}

 

// другие методы класса

. . .


 

Рассмотрим примеры реализации сохранения-восстановления объектов.

 

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

Рассмотрим некоторое приложение, документ которого представляет собой единственную текстовую строку, которая выводится на экран классом представления. Предусмотрим в работе приложения три команды меню. При первом запуске текст сообщения автоматически устанавливается как Default Message. Его можно изменить, выполнив команду меню Edit->Change Message. Сохранить документ можно с помощью команды File->Save, а вновь загрузить — с помощью File->Open.



Классы документа

Способность объектов сохраняться после изменения в одном сеансе и восстанавливать свое состояние в следующем, используя файл в качестве промежуточной среды хранения, есть ничто иное, как живучесть объектов с точки зрения пользователя. Рассмотрим реализацию концепции сохранения-восстановления в приложениями, созданными с помощью AppWizard.

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

1. Создание членов-переменных класса документа, которые будут хранить специфические для данного вида документа данные.

2. Инициализация этих членов-переменных в методе OnNewDocument( ) класса документа.

3. Организация отображения текущего состояния документа в методе OnDraw() класса представления.

4. Включение в класс представления методов, обеспечивающих редактирование документа.

5. Модификация метода Serialize() класса документа — включение в него операторов, обеспечивающих сохранение и загрузку данных, которые и представляют собой содержание документа.

Что касается МDI-приложений; то, помимо перечисленных операций, придется сделать кое-что дополнительно, поскольку нужно обеспечить правильный выбор сохраняемого и корректную загрузку восстанавливаемого документов с учетом того, что приложение такого типа работает в течение одного сеанса с множеством документов одновременно. К счастью, большую часть этих функций MFC реализует без участия программиста.

Рассмотрим SDI—приложение My, построенное AppWizard и поддерживающее архитектуру документ/представление.

Определим данные, с которыми работает представление. Добавим в секцию атрибутов класса CMyDoc (в файле MyDoc.h) определение переменной m_message ,типа CString, чтобы этот фрагмент определения класса выглядел следующим образом:

//Атрибуты.

public:

CString m_message;

В данном случае документ содержит единственный объект класса CString— строку текста. В реальных приложениях данные будут значительно сложнее. Однако этой единственной строки текста хватит, чтобы продемонстрировать особенности технологии обеспечения сохранности документа. Очень часто программисты используют в классе документа открытые члены-переменные вместо закрытых членов, для каждого из которых организуется открытая функция доступа. Это несколько облегчает разработку класса представления, методы которого должны обращаться к членам класса документа. Но в дальнейшем при сопровождении программы и, в частности, ее модификации такой подход несколько усложнит жизнь.

Класс документа также должен обеспечить инициализацию данных при открытии нового документа, что возлагается на метод OnNewDocument( ) этого класса. Вызовите при помощи окна ClassView текст этой функции в окно редактора кода и отредактируйте его. Добавьте оператор инициализации строковой переменной.

BOOL CMyDoc::OnNewDocument()

{if(!CDocument::OnNewDocument())

return FALSE;

m_message = "Default Message";

return TRUE;}

После того, как переменная m_message—член класса документа— инициализирована, приложение должно вывести содержимое документа в свое окно. Здесь за дело берется метод OnDraw() класса представления. Вывести, текст этой функции в окно редактора кода можно уже известным вам способом при помощи окна Class View. После редактирования функция должна иметь вид:

void CMyView: :OnDraw(CDC* рDС)

{CMyDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

pDC->TextOut(20,20, pDoc->m_message);

}

Если оттранслировать приложение My и запустить его на выполнение, вы увидите, что на экране появится сообщение Default Message.

Теперь необходимо обеспечить возможность редактирования. Для того чтобы обеспечить такую возможность, нужно включить в меню Edit приложения пункт Change Message. По этой команде должны запускаться средства, позволяющие пользователю изменить текст документа — выводимого сообщения.

Щелкните на вкладке Resource в левой части экрана и вызовите окно ResourceView, разверните компонент Menu и дважды щелкните на IDR_MAINFRAME. Теперь можно приступить к редактированию меню. Щелкните на пункте Edit и разверните его. Щелкните на пустом поле внизу списка пунктов этого меню и введите Change &Message. В результате в меню будет добавлен новый пункт.

Теперь вызовите мастер СlassWizard. Он понадобится вам для установления связи между новой командой и текстом программы. В левом окне ClassWizard должен быть подсвечен пункт ID_EDIT_CHANGEMESSAGE. Если это не так, щелкните на этом пункте. В раскрывающемся .списке справа вверху выберите CMyView. Щелкните на COMMAND в окне справа, а затем— на кнопке Add Function.

Предлагаемое мастером имя функции OnEditChangemessage () нам вполне подходит, так что щелкните на кнопке ОК в появившемся диалоговом окне. Теперь щёлкните на кнопке Edit Code — заготовка новой функции будет выведена в окне редактора кода. Ее нужно отредактировать.

Void CmyView::OnEditChangemessage,() .{

CTime now = CTime::GetCurrentTime();

CString changetime = now.Format("Changed at %B %d %H:%M:%S");

GetDocument()->m_message = changetime;

GetDocument()->SetModifiedFlag();

Invalidate();}

Эта функция, формирует строку соответственно текущей дате и времени и присваивает ее переменной-члену текущего объекта класса документа. Вызов метода SetModifiedFlag() класса документа сообщит приложению, что содержимое документа изменено. Если такое изменение зафиксировано, приложение будет предупреждать пользователя о наличии несохраненных изменений в текущем документе при попытке его закрыть. И последняя операция — запуск механизма обновления представления документа на экране, .который производится функцией Invalidate().

Если m_message является закрытой переменной-членом класса документа, понадобится разработать открытый метод SetMessage(), который будет самостоятельно вызывать SetModifiedFlagO. Таким образом, вы будете навсегда избавлены от необходимости напоминать программистам об обязательном обращении к этой функции при модификации объекта класса документа. В этом и состоит преимущество скрупулезного следования принципам объектно-ориентированного программирования.

Метод Serialize() класса документа должен позаботиться о сохранении-восстановлении данных документа. Текст заготовки функции Serialize(), сформиpoвaнный AppWizard, выглядит следующим образом

void CMyDoc::Serialize(CArchive& ar)

{if (ar.IsStoring())

{//}

else{//TODO: сюда вставьте операторы загрузки данных.}}

Поскольку в классе CString (объектом которого является переменная m_message) определены терминальные операторы >> и << для передачи данных в архив и из него, это значительно упрощает сохранение и восстановление данных в объекте класса документа. Добавьте следующий оператор в том месте, где в заготовке стоит инструктирующий комментарий:

ar<< m_message;

Аналогично в том месте текста программы, где должны стоять операторы загрузки, вставьте

ar>> m_message;

 

Терминальный оператор << пересылает CString m_message в архив, а терминальный оператор >> заносит данные в m_message из архива. До тех пор, пока данные документа сохраняются в члене— простой переменной (наподобие int или char) или в объекте такого класса, как CString, для которых определены соответствующие терминальные операторы, сохранение и восстановление документа выполняются очень просто. Указанные терминальные операторы определены для следующих простых типов данных.

• BYTE •

• WORD

• int

• LONG

• DWORD

• float

• double

Оттранслируйте приложение My и запустите его. Выберите в меню приложения Edit=>Change Message и убедитесь, что на экране появилась новая строка сообщения, Changed at …. Теперь выберите File->Save и введите имя файла. Опять измените текст сообщения с помощью команды Edit->Change Message. Выберите File->New— на экране появится предупреждающее сообщение о наличии в документе несохраненных изменений. Вам будет предложено сохранить их на диске прежде, чем открывать новый документ. Теперь выберите File=>0pen и введите имя ранее созданного файла документа (его можно найти и в списке в самом низу меню File). После этого на экране появится ранее сохраненный текст сообщения. Таким образом, вы можете убедиться, что приложение My сохранило документ по вашей команде, а затем восстановило его в прежнем виде.

 

Если в документ внесены изменения, он сохранен в файле, в него внесены новые изvенения и вызвана команда открыть файл с тем же именем, приложение My не будет выводить запрос Revert to saved document? (Вернуться к сохраненному документу?), как это делают другие программы. Вместо этого перед вами на экране будет самая последняя версия документа. Такой механизм встроен теперь в MFC. Если имя открываемого файла соответствует имени текущего, вы не сможете вернуться к прежней версии документа.

 










Последнее изменение этой страницы: 2018-04-12; просмотров: 245.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...