Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Сериализация, наверное, не знаю как тему назвать правильно 
:(
    Опции темы
Alek86
Дата 18.2.2008, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



а терь для совсем тупых
есть у меня вектор Base'ов. В нем находятся потомки в последовательности:
Derived1, Derived2, Derived1, Derived1, Derived2
засериализировать вектор легко

КАК его снова получить из потока? как узнать, что для 0-го элемента требуется вызвать Deserialize у Derived1б для 1-го - у Derived2 и т.д.?


--------------------
user posted image    user posted image
PM MAIL   Вверх
Lazin
Дата 18.2.2008, 12:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Сохраняй числовые идентификаторы, по ним определяй что создавать и читать...
PM MAIL Skype GTalk   Вверх
Alek86
Дата 18.2.2008, 12:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(Lazin @  18.2.2008,  12:23 Найти цитируемый пост)
по ним определяй что создавать и читать...

и как сюда приткнуть красивейшую полиморфическую схему, предложенную ранее (имхо, очевидную, ибо вся трудность в этой связке)


--------------------
user posted image    user posted image
PM MAIL   Вверх
xvr
Дата 18.2.2008, 12:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(georain @ 15.2.2008,  15:18)
Вот приходят из сети данные блоками, в начале блока есть число - идентификационный номер класса который он содержит. Нужно преобразовать блок в класс с помощью статической функции этого класса.
Пользоваться case не хочу, классов много, хочу чтобы работало быстро smile

Насколько быстро надо? Если умеренно быстро, то можно в качестве ID взять не просто число а пару - строку, с именем типа класса и хэш от этой строки. Если хэш будет достаточно хороший (в идеале без колизий вообще), то определение типа класса сведется просто к индексации массива с хэшами.

Реализация:
1) Для получения имен типов используется RTTI
2) Все типы классов должны наследоваться от базового, содержащего примитивы для сериализации
3) Для регистрации классов используется специальный темплэйтный класс - фабрика.
Код

class BaseSerializable {
public:
 virtual void serialize(ostream&) =0;
 virtual void deserialize(istream&) =0;
};

class BaseFabric {
protected:
 void registrate(const char* id, BaseFabric* creator);
public:
 virtual BaseSerializable* create() =0;
};

template <class Item>
class Fabric : public BaseFabric {
public:
 Fabric() {registrate(typeid(Item).name(),this);}
 virtual BaseSerializable* create() {return new Item;}
};
#define CREATE_FABRIC(Type) static Fabric<Type> instance_of_class_fabric_for_##Type;


При записи сначала пишется ID класса (хэш(typeid(Item).name()) и typeid(Item).name()), затем сам класс (методом serialize). Опционально можно проверить, что данный ID был зарегистрированн какой либо фабрикой классов (Fabric<xxx>)
При чтении читается ID, ищется среди зарегистрированных фабрик (в идеале просто индексируется массив), создается класс, заполняется из потока



Это сообщение отредактировал(а) xvr - 18.2.2008, 12:45
PM MAIL   Вверх
marcusmae
Дата 18.2.2008, 13:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


stravaganza
**


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

Репутация: 5
Всего: 39



Цитата(Alek86 @  18.2.2008,  11:42 Найти цитируемый пост)
есть у меня вектор Base'ов. В нем находятся потомки в последовательности:Derived1, Derived2, Derived1, Derived1, Derived2засериализировать вектор легко


Цитата(Alek86 @  18.2.2008,  11:42 Найти цитируемый пост)
а терь для совсем тупых

Хорошо, перефразирую. Тип Вы восстановите, я не сомневаюсь (Леонардо да Винчи плакаль бы от приведённых здесь неистовых механизмов осуществления этого). Мне непонятно, что Вы будете делать в случае неоднозначности соответствия сериализованного экземпляра и "места", в которое его нужно десериализовать. Так что, в этой постановке,
Цитата

КАК его снова получить из потока?

ответ : НИКАК. Ещё вопросы? smile

Это сообщение отредактировал(а) marcusmae - 18.2.2008, 13:10


--------------------
ἀπὸ μηχανῆς θεός
PM MAIL ICQ GTalk   Вверх
georain
Дата 18.2.2008, 13:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



В общем ничего лучше чем в первом после я не услышал, замечания tol05 относятся к методам сериализации/десериализации, т.е. как упаковать/распаковать класс, это совсем другая проблема. На счёт создания в конструкторе: новый класс можно создавать с параметрами конструктора взятые из потока в той-же функции create(). 
Код

    static Base * create(CDR * cdr){
        return new ClassA(cdr->getMember());
    };  

Надо не забывать что доступ к коду и клиента и сервера одновременно не всегда возможен. Иногда есть только протокол. И третий момент, что не всегда нужно передавать по сети весь класс целиком, часто нужны только некоторые его члены.
Была приведена функция 
Код

void Serialize(char* stream)

, хорошо, допусти мы работаем по этой методике, как эту функцию Serialize вызвать для нужного класса?

tol05 я очень благодарен что хочешь помочь, но мысль совсем не понятна.
Цитата(tol05 @  16.2.2008,  19:33 Найти цитируемый пост)
А вот если через конструктор базового класса (с параметром потоком) делать... то его бы не было smile
и никаких индексов... они просто не имеют смысла в последовательном и единственном потоке.

Ну как тогда без индексов классифицировать классы и вообще отделять один класс от другого в потоке?

А изначальная проблема для этой задачи кстати звучит очень просто: есть дерево под сотню классов, набор экземпляров этих классов надо максимально эффективно отправлять по сети, причем последовательность типов экземпляров и их количество заранее не известно.

В общем вопрос открытый.

P.S. Alek86, кстати строчка
Код

   #define f(CN)   VFunc[n##CN] = CN::create;

проверят существует ли переменная nNameClass, если ее в enume нет, то ошибку выведет. Поэтому проверка enum'а нужна только на отравляющей стороне (а там проверка находится в функции "сериализации" при вставке константы из enum'а в поток).

Добавлено через 13 минут и 29 секунд
marcusmae, ну это же может быть вектор указателей на Base)

Это сообщение отредактировал(а) georain - 18.2.2008, 13:23
PM MAIL   Вверх
tol05
Дата 18.2.2008, 13:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 1
Всего: 170



Да действительно, если мы имеем сложный класс MyClass, серилизуем в один и тот же поток 10 его экземпляров, а десерилизовать нужно будет (к примеру) только 2-й и 8-й....

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

Здесь нужно написать базовую функциональность серилизации, а как ее применять - уже зависит от конкретного случая использования...

Вот как, например, сказать глупой машине, чтобы среди много-много байтов она нашла только те, которые относятся только к тому классу, у которого 23-й член равен 17?  smile 

Я описывал только паттерн (композитор ИМХО), реализованный в .Net, в частности.





--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Alek86
Дата 18.2.2008, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(marcusmae @  18.2.2008,  13:05 Найти цитируемый пост)
ответ : НИКАК. Ещё вопросы? 

ты не веришь, что десериализация возможна? )


Цитата(georain @  18.2.2008,  13:12 Найти цитируемый пост)
 если ее в enume нет, то ошибку выведет.

да, похоже... перемудрил я )
тогда порекомендую вместо массива указателей на функции пользовать map и вызов с помощью cdr.getNumber() в try-блок обернуть...

Добавлено через 2 минуты и 46 секунд
Цитата(tol05 @  18.2.2008,  13:37 Найти цитируемый пост)
Да действительно, если мы имеем сложный класс MyClass, серилизуем в один и тот же поток 10 его экземпляров, а десерилизовать нужно будет (к примеру) только 2-й и 8-й....

помойму, tol05, ты не совсем понимаешь, в чем вопрос. Вопрос, как отличать разных наследников в списке. Если на это есть "паттерн" - с удовольствием выслушаю (говорю без стеба) smile


--------------------
user posted image    user posted image
PM MAIL   Вверх
georain
Дата 18.2.2008, 14:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Цитата(Alek86 @  18.2.2008,  13:46 Найти цитируемый пост)
тогда порекомендую вместо массива указателей на функции пользовать map и вызов с помощью cdr.getNumber() в try-блок обернуть...

Вот я вот этого не понимаю,  зачем map то нужен?

Это сообщение отредактировал(а) georain - 18.2.2008, 14:07
PM MAIL   Вверх
Alek86
Дата 18.2.2008, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



чтобы исключения кидать, когда айди несуществующий функция cdr.getNumber() отдаст

в твоем же случае боюсь подумать, что получится. отдастся какое-то число, оно посчитается указателем на функцию и запустится...

Добавлено через 1 минуту и 30 секунд
а заместо указателей на функции использовать boost::function чтоб и от других ошибок отгородиться


--------------------
user posted image    user posted image
PM MAIL   Вверх
tol05
Дата 18.2.2008, 14:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 1
Всего: 170



Теперь понял. Конечно есть паттерн, как не быть.  smile 

каждый объект, серилизуясь, записывает в поток имя своего класса (в качестве своей системной информации, например)

Делаем класс - фабрику, куда передаем имя класса и поток. Фабрика создает объект нужного класса. Она ищет в потоке фрагменты данных, соответствующие требуемому классу. Если таких объектов - несколько, перегружаем методы фабрики и добавляем в запросы к фабрике параметры, конкретизирующие поиск.

P.S. все, больше мешать не буду. ИМХО решите проблему концептуально сначала. smile

P.S.S указателей не передавайте. Где гарантия уникальности значений? При десерилизации из нескольких потоков? На различных клиентах?

Это сообщение отредактировал(а) tol05 - 18.2.2008, 14:27


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Alek86
Дата 18.2.2008, 14:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(tol05 @  18.2.2008,  14:19 Найти цитируемый пост)
Делаем класс - фабрику, куда передаем имя класса и поток. Фабрика создает объект нужного класса. Она ищет в потоке фрагменты данных, соответствующие требуемому классу. Если таких объектов - несколько, перегружаем методы фабрики и добавляем в запросы к фабрике параметры, конкретизирующие поиск.

немного неясная формулировка. короче говоря, нужно делать ту же карту, только между строкой и соответствующей функцией фабрики? тогда это практически то же, что и в первом посте.


--------------------
user posted image    user posted image
PM MAIL   Вверх
Lazin
Дата 18.2.2008, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3820
Регистрация: 11.12.2006
Где: paranoid oil empi re

Репутация: 41
Всего: 154



Ну вы тут напридумывали сами себе сложностей  smile 
вот приблизительный код, никаких имен классов, boost::function, и прочего. Похожий код использовал в одном проекте, этот в качестве иллюстрации на коленке написал за пару минут))

Код

//базовый класс

class Base
{
    virtual void save_(std::ostream&) = 0;
    virtual void load_() = 0;
public:
    void save(std::ostream& s)
    {
        save(s);
    }
    
    void load(std::istream& s)
    {
        load_(s);
    }
    
    /***************/
};

typedef Base* (base_factory_fn*)(std::istream&);

//global
std::map<int, base_factory_fn> BaseFactory;//это не обязательно map, может быть к примеру простой массив

//наследник
class Derived1 : public Base
{
    int field;
    virtual void save_(std::ostream& s)
    {
        s << type_trait;
        s << field;
    }
    virtual void load_(std::istream& s)
    {
        s >> field;
    }
public:
    enum {type_trait = 1};
    static Base* Make (std::istream& s)
    {
        Base* p = new Derived1(/*детали конструирования Derived1*/);
        p->load(s);//можно написать к примеру конструктор который будет принимать ссылку на поток и читать все оттуда, но это имхо дурной стиль
        return p;
    }
    
    /***************/
};

namespace{//регистрация класса Derived1
    class Reg1
    {
    public:
        Reg1()
        {
            BaseFactory[Derived1::type_trait] = &Derived1::Make;
        }
    };
    Reg1 register_derived_1;
};

class Derived2 : public Base
{
    std::string field;
    virtual void save_(std::ostream& s)
    {
        s << type_trait;
        s << field;
    }
    virtual void load_(std::istream& s)
    {
        s >> field;
    }
public:
    enum {type_trait = 2};
    static Base* Make (std::istream& s)
    {
        Base* p = new Derived2(/*детали конструирования Derived2*/);
        p->load(s);
        return p;
    }
    /***************/
};

namespace{//регистрация класса Derived2
    class Reg2
    {
    public:
        Reg2()
        {
            BaseFactory[Derived2::type_trait] = &Derived2::Make;
        }
    };
    Reg2 register_derived_2;
};



std::vector<Base*> base_array;
.....
out_str - ostream - поток в который сохраняются объекты
....
сохранение:
for (std::vector<Base*>::iterator i = base_array.begin(); i != base_array.end(); ++i)
{
    i->save(out_str);
}
........
inp_str - istream - поток для чтения
.......
восстановление 1-го объекта:

int trait = 0;
inp_str >> trait;
Base* p = BaseFactory[trait](inp_str);


PM MAIL Skype GTalk   Вверх
tol05
Дата 18.2.2008, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


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

Репутация: 1
Всего: 170



я бы не сказал, что то же smile
Похоже конечно, но ведь мы все говорим на одну тему, поэтому и посты как бы об одном и том же...

Ты получаешь пакеты данных. Это во-первых. Вначале пакета идет его идентификатор. Замечательно. 
Цитата(georain @  15.2.2008,  14:18 Найти цитируемый пост)
Вот приходят из сети данные блоками, в начале блока есть число - идентификационный номер класса который он содержит. Нужно преобразовать блок в класс с помощью статической функции этого класса.

Получил ты число 12667845 например... Нужно создать какой-то класс. Какой? "с помощью статической функции какого класса"?

передаешь принятый пакет (поток) в фабрику. Она считывает из потока блок данных до определенной метки. Это имя класса. Дальше нужно создать экземпляр. Рефлексия в плюсах есть? Позднее связывание? Класс Activator, я имею в виду? marcusmae, здесь точно ответит. я - нет...

Но даже если и нет... Простой оператор switch по текстовому значению вызывает ф-цию ISerializable.Deserialize для каждого конкретного класса, а-ля
Код

ISerializable result = null;
switch(ClassName)
         {
                case "A": result = ((ISerializable)(new A())).Deserialize()); break;
                case "B": result = ((ISerializable)(new B())).Deserialize()); break;         
         }
return result;

и т.д.

сделайте абстракный класс, как говорилось выше. Если хотите полиморфности.


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
Alek86
Дата 18.2.2008, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



и tol05 и Lazin, фактически, предлагают одно и то же smile все равно решение аввтора покрасивше
в С++ нету свича для строк + мап полюбому получше от свича.
а у Lazin оно не так автоматизировано, как в пером посте

+ боюсь представить, что ЭТО такое. какой у этого класса размер?
Код

class Reg2
    {
    public:
        Reg2()
        {
            BaseFactory[Derived2::type_trait] = &Derived2::Make;
        }
    };
    Reg2 register_derived_2;
};



--------------------
user posted image    user posted image
PM MAIL   Вверх
Страницы: (4) Все 1 [2] 3 4 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




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


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

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