Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сериализация, Нужно сериализовать иерархию объетов 
:(
    Опции темы
RobinHoodPHD
Дата 19.6.2010, 10:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 78
Регистрация: 12.8.2007
Где: Русь

Репутация: нет
Всего: 2



Доброго времени суток, Господа!

Продолжаю свое мытарство с программой для рисования  smile ))) Дело дошло до сохранения моих кружков-линий-прямоугольничков на диск и их чтения с него. В меру своего понимания я переопределил функцию Serialize моего объекта документа:
Код

void CSDI1Doc::Serialize(CArchive& ar)
{
    CObject * el;
    if (ar.IsStoring())
    {
        // TODO: add storing code here
        POSITION pos;
        for( pos = ObjectList.GetHeadPosition(); pos != NULL; )
        {
            el = (CObject *) ObjectList.GetNext (pos);
            el->Serialize (ar);
        }
    }
    else 
    {
        while ( !ar.IsBufferEmpty ()) {
            el->Serialize (ar);
            ObjectList.AddTail (el);
        }
        }
}

Где ObjectList - это экземпляр CObList хранящий мои фигуры. Каждая фигура представлена классом, производным от абстрактного класса Geom, который сам наследует от CObject;
Вот такая иерархия:
CObject 
Geom (абстрактный)
RCircle, RLine, RRect, ... RDot      - это классы моих фигур

Для каждого класса фигуры я переопределил функцию Serialize, например для класса класса RCircle:
Код

void RCircle::Serialize (CArchive &ar) {
if (ar.IsStoring()){
    ar << State;
    ar << center;
    ar << rad;
}
else {
    ar >> State;
    ar >> center;
    ar >> rad;
}
}

Класс описан с макросом DECLARE_SERIAL(RCircle) и в реализации есть IMPLEMENT_SERIAL(RCircle, CObject, 1)

Сохранять - вроде сохраняет, по крайней мере строка el->Serialize (ar); вызывает функцию Serialize именно для RCircle. Проблема теперь с тем, как это прочитать. Ведь я не знаю какого типа я читаю объект - окружность, линию или чего еще. Кусок кода из CSDI1Doc::Serialize для чтения явно у меня не задался )) и не работает.
Код

    else 
    {
        while ( !ar.IsBufferEmpty ()) {
            el->Serialize (ar);
            ObjectList.AddTail (el);
        }
        }

Во-первых цикл ни разу не прокручивается => буфер всегда пустой, хотя я вроде сериализовал 3 окружности и сам файл не нулевого размера.

В общем вопрос - что я сделал не так, и что мне исправить, чтобы сохранить и восстановить мои объекты.  smile 

Заранее благодарен за Ваши ответы на мое, немного сумбурное, и путанное изложение проблемы)
PM MAIL   Вверх
Earnest
Дата 20.6.2010, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Разумеется, перед телом объекта нужно писать его тип. Это можно делать самому или довериться MFC: если для объекта определить макрос DECLARE_SERIAL \ IMPLEMENT_SERIAL, то объект будет сериализоваться сам. Конечно, это не означает, что для абстрактного указателя модно вызвать Serialize, и он каким-то чудом превратится в объект нужного типа (я имею в виду загрузку). Не помню, как это именно происходит в MFC, но схема примерно такая: как я уже говорила, перед телом объекта обязательно записывается его тип - в виде числа или в виде строки, да хоть GUID - на что фантазии хватит. Далее, реализуется фабрика, которая принимает поток (архив) и возвращает объект. Фабрику можно реализовать как отдельный объект, либо как функцию. Если особых наворотов не требуется, то я бы ограничилась статической функцией. Тогда чтение будет выглядеть примерно так:
Код

   while ( !ar.IsBufferEmpty ()) 
   {
            el = CGeom::Create (ar);
            ObjectList.AddTail (el);
    }

    CGeom* CGeom::Create (CArchive& ar)
   {
        ASSERT (Ar.IsLoading());
        WORD type;
        ar >> type;
        // а дальше хоть switch, который создает объект нужного типа
        CGeom* pObj = ...
       pObj->Serialixe (ar);
    }

Ну, switch - это, конечно, если совсем лениво или иерархия объектов простая как тапок и не предполагает развития. Лучше делать объекты само-регистрирующимися. Собственно, DECLARE_SERIAL примерно так и действует. Подробностей не помню, т.к. в свое время мне что-то там не понравилась, и я предпочитаю организовывать фабрики сама. Но суть одна.


--------------------
...
PM   Вверх
RobinHoodPHD
Дата 21.6.2010, 20:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 78
Регистрация: 12.8.2007
Где: Русь

Репутация: нет
Всего: 2



Спасибо огромное, Earnest !! Так и сделал - работает как часы. 
Единственное что не работает- это ar.IsBufferEmpty () - всегда возвращает false, поэтому я просто переделал так:
Код

void CSDI1Doc::Serialize(CArchive& ar)
{
....
if (ar.IsStoring())
{ ..... }
else {
    while ( (el = (CObject*) Geom::Create (ar)) != NULL) {
        ObjectList.AddTail (el);
    }
}

} // CSDI1Doc::Serialize

Geom* Geom::Create (CArchive& ar)
{
 Geom* pObj;
WORD type;
try {
    ar >> type;
    switch (type) {
        case CIRCLE : pObj = (Geom*) new RCircle (); break;
    }    
    pObj->Serialize (ar);
    return pObj;
    }
    catch (...) {
        return NULL;
    }
}



PM MAIL   Вверх
Earnest
Дата 22.6.2010, 07:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 87
Всего: 183



Цитата(RobinHoodPHD @  21.6.2010,  21:29 Найти цитируемый пост)
Единственное что не работает- это ar.IsBufferEmpty () 

Просто эта функция делает не то, что ты полагаешь. 
Цитата

This function is supplied to support programming with the MFC Windows Sockets class CSocketFile. You do not need to use it for an archive associated with a CFile object. 

Я обычно проверяю конец чтения просто по факту непрочтения очередной порции байтов: перед чтением каждого объекта ведь нужно прочесть его тип. Получается как-то так:
   if (ar.Read (&type, sizeof(type) != sizeof(type)) -> приплыли.
Ну, и разумеется, try-catch не помешает для аварийных ситуаций (порча файла и т.д.)


--------------------
...
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Visual C++/MFC/WTL | Следующая тема »


 




[ Время генерации скрипта: 0.0484 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.