2013-03-06 3 views
2

В моем приложении есть агенты разных типов. Я планирую использовать форсированную сериализацию для отправки/получения данных между агентами (путем отправки/получения, я на самом деле подразумеваю операцию записи/чтения файла цепочки сериализации)правильный тип-литой для ускорения де-сериализации разных производных классов

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

class Base 
{ 
public: 
    int message_type_id; 
} 

class Derived_1 
{ 
public: 
Derived_1(int message_type_id_):message_type_id(message_type_id_){} 
struct data_1 {...}; 
}; 


class Derived_2 
{ 
public: 
Derived_2(int message_type_id_):message_type_id(message_type_id_){} 
struct data_2 {...}; 
}; 

отправляющий агент может отправить (т.е. сериализации) любого из двух типов производных. Аналогично, принимающий агент может получать (то есть де-сериализует) любой из двух производных типов; а то, что я могу видеть в tutorial(Dumping derived classes through base class pointers), как это:

void save() 
{ 
    std::ofstream file("archive.xml"); //target file 
    boost::archive::xml_oarchive oa(file); 
    oa.register_type<date>();// you know what you are sending, so you make proper modifications here to do proper registration 
    base* b = new date(15, 8, 1947); 
    oa & BOOST_SERIALIZATION_NVP(b); 
} 

void load() 
{ 
    std::ifstream file("archive.xml"); //target file 
    boost::archive::xml_iarchive ia(file); 
    ia.register_type<date>();// I don't know which derived class I am receiving, so I can't do a proper registration 
    base *dr; 
    ia >> BOOST_SERIALIZATION_NVP(dr); 
    date* dr2 = dynamic_cast<date*> (dr); 
    std::cout << dr2; 
} 

, как вы можете видеть, xml_oarchive и xml_iarchive сделать register_type<date> до сериализации/десериализации. поэтому получающая сторона будет знать заранее, что до dynamic_cast. , тогда как в моем случае, так как я знаю, что я отправляю, я могу сделать правильную регистрацию & сериализации на основе case-to-case. Тем не менее, на принимающей стороне, я не знаю заранее, что регистрировать, а что - динамически.

Есть ли способ, которым я могу заранее указать тип, чтобы получающий мог сделать кастинг?

благодаря

EDIT: Вот упрощенная модификация demo.cpp я сохранить объект, а затем восстановить его.

#include <cstddef> // NULL 
#include <iomanip> 
#include <iostream> 
#include <fstream> 
#include <string> 

#include <boost/archive/tmpdir.hpp> 

#include <boost/archive/text_iarchive.hpp> 
#include <boost/archive/text_oarchive.hpp> 

#include <boost/serialization/base_object.hpp> 
#include <boost/serialization/utility.hpp> 
#include <boost/serialization/list.hpp> 
#include <boost/serialization/assume_abstract.hpp> 

/* 
bus_stop is the base class. 
bus_stop_corner and bus_stop_destination are derived classes from the above base class. 
bus_route has a container that stores pointer to the above derived classes 
*/ 

class bus_stop 
{ 
    friend class boost::serialization::access; 
    virtual std::string description() const = 0; 
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version) 
    { 
     ar & type; 
    } 
protected: 
public: 
    std::string type; 
    bus_stop(){type = "Base";} 
    virtual ~bus_stop(){} 
}; 

BOOST_SERIALIZATION_ASSUME_ABSTRACT(bus_stop) 

class bus_stop_corner : public bus_stop 
{ 
    friend class boost::serialization::access; 
    virtual std::string description() const 
    { 
     return street1 + " and " + street2; 
    } 
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version) 
    { 
     // save/load base class information 
     ar & boost::serialization::base_object<bus_stop>(*this); 
     ar & street1 & street2; 
    } 

public: 
    std::string street1; 
    std::string street2; 
    bus_stop_corner(){} 
    bus_stop_corner(
     const std::string & _s1, const std::string & _s2 
    ) : 
     street1(_s1), street2(_s2) 
    { 
     type = "derived_bs_corner"; 
    } 
}; 

class bus_stop_destination : public bus_stop 
{ 
    friend class boost::serialization::access; 

    virtual std::string description() const 
    { 
     return name; 
    } 
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version) 
    { 
     ar & boost::serialization::base_object<bus_stop>(*this) & name; 
    } 
public: 
    std::string name; 
    bus_stop_destination(){} 
    bus_stop_destination(
     const std::string & _name 
    ) : 
     name(_name) 
    { 
     type = "derived_bs_destination"; 
    } 
}; 

class bus_route 
{ 

    friend class boost::serialization::access; 
    typedef bus_stop * bus_stop_pointer; 
    template<class Archive> 
    void serialize(Archive &ar, const unsigned int version) 
    { 
     ar.register_type(static_cast<bus_stop_corner *>(NULL)); 
     ar.register_type(static_cast<bus_stop_destination *>(NULL)); 
     ar & stops; 
    } 
public: 
    std::list<bus_stop_pointer> stops; 
    bus_route(){} 
    void append(bus_stop *_bs) 
    { 
     stops.insert(stops.end(), _bs); 
    } 
}; 

//BOOST_CLASS_VERSION(bus_route, 2) 

void save_schedule(const bus_route s, const char * filename){ 
    // make an archive 
    std::ofstream ofs(filename); 
    boost::archive::text_oarchive oa(ofs); 
    oa << s; 
} 

void 
restore_schedule(bus_route &s, const char * filename) 
{ 
    // open the archive 
    std::ifstream ifs(filename); 
    boost::archive::text_iarchive ia(ifs); 
    // restore the schedule from the archive 
    ia >> s; 
} 

int main(int argc, char *argv[]) 
{ 
    bus_stop *bs1 = new bus_stop_corner(
     "First St", "Second st" 
    ); 
    bus_stop *bs2 = new bus_stop_destination(
     "myName" 
    ); 

    // make a routes 
    bus_route original_route; 
    original_route.append(bs1); 
    original_route.append(bs2); 

    std::string filename1(boost::archive::tmpdir()); 
    filename1 += "/demofile1.txt"; 

    save_schedule(original_route, filename1.c_str()); 
    bus_route new_route ; 

    restore_schedule(new_route, filename1.c_str()); 
//////////////////////////////////////////////////////// 
    std::string filename2(boost::archive::tmpdir()); 
    filename2 += "/demofile2.txt"; 
    save_schedule(new_route, filename2.c_str()); 

    delete bs1; 
    delete bs2; 
    return 0; 
} 

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

EDIT-2 В приведенном выше кодексе нет ничего плохого (после того, как была исправлена ​​небольшая опечатка). Я отвечаю на свой вопрос здесь, потому что есть другой хороший подход, предложенный кем-то другим. Итак, Ответьте на мой первый вопрос: Пока вы регистрируете производные типы в главной функции сериализации (в приведенном выше случае: serialize() в классе bus_route) все должно быть хорошо.

спасибо за помощь

ответ

2

Раствор является (де-) сериализовать boost::shared_ptr<Base>. Следующий код демонстрирует это. После десериализации pDst является экземпляром класса Derived_1. Код, выполненный с использованием онлайн-компилятора, доступен по адресу this link.

#include <boost/serialization/access.hpp> 
#include <boost/serialization/assume_abstract.hpp> 
#include <boost/serialization/shared_ptr.hpp> 
#include <boost/serialization/nvp.hpp> 
#include <boost/noncopyable.hpp> 
#include <boost/make_shared.hpp> 
#include <boost/smart_ptr/shared_ptr.hpp> 

class Base { 
    friend class boost::serialization::access; 
public: 
    Base(); 
    virtual ~Base(); 
private: 
    template<class Archive> void serialize(Archive &ar, const unsigned int version) {} 
public: 
    virtual bool operator ==(const Base &rh) const = 0; 
}; 

BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base) 
BOOST_SERIALIZATION_SHARED_PTR(Base) 

Base::Base() { 
} 

Base::~Base() { 
} 

class Derived_1 : boost::noncopyable, public Base { 
    friend class boost::serialization::access; 
public: 
    int m_iValue; 
public: 
    Derived_1(); 
    Derived_1(int iValue); 
private: 
    template<class Archive> void serialize(Archive &ar, const unsigned int version) { 
     ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); 
     ar & boost::serialization::make_nvp("value", m_iValue); 
    } 
public: 
    bool operator ==(const Base &rh) const; 
}; 

BOOST_SERIALIZATION_SHARED_PTR(Derived_1) 

Derived_1::Derived_1() : m_iValue(0) { 
} 

Derived_1::Derived_1(int iValue) : m_iValue(iValue) { 
} 

bool Derived_1::operator==(const Base &rh) const { 
    const Derived_1 *pRH = dynamic_cast<const Derived_1 *>(&rh); 
    return pRH != nullptr && pRH->m_iValue == this->m_iValue; 
} 

#include <boost/serialization/export.hpp> 
#include <boost/archive/xml_oarchive.hpp> 
#include <boost/archive/xml_iarchive.hpp> 

#include <boost/make_shared.hpp> 
#include <sstream> 
#include <string> 

BOOST_CLASS_EXPORT_GUID(Base, "base") 
BOOST_CLASS_EXPORT_GUID(Derived_1, "derived_1") 

void test(void) { 
    std::string str; 
    boost::shared_ptr<Base> pSrc = boost::make_shared<Derived_1>(10); 
    boost::shared_ptr<Base> pDst; 
    { 
     std::ostringstream ofs; 
     boost::archive::xml_oarchive oa(ofs); 
     oa << boost::serialization::make_nvp("item", pSrc); 
     str = ofs.str(); 
    } 
    { 
     std::istringstream ifs(str); 
     boost::archive::xml_iarchive ia(ifs); 
     ia >> boost::serialization::make_nvp("item", pDst); 
    } 
    if (*pSrc == *pDst) { 
     printf("Success\n"); 
    } 
    else { 
     printf("Fail\n"); 
    } 
} 

int main(int argc, char* argv[]) { 
    test(); 
} 
+0

@ meabyte1024 благодарит за прекрасный ответ. Но, будучи новичком в сериализации, я не понимаю, как использование справки XML и общей версии <> позволяет решить проблему. Я думаю, что более одного типа производного класса не изменят правильный результат. Как он работает, даже не регистрируя производные классы? – rahman

+1

@rahman, давайте выясним, в чем проблема. Как только я понял, вам нужно десериализовать производные классы, не имеет значения, либо это «Derived_1» или «Derived_2». Правильно ли это?Если да, то мой пример демонстрирует это. Часть десериализации функции 'test' работает с экземпляром класса' boost :: shared_ptr '(' pDst'), и сериализация создает правильный экземпляр производного класса. Программа выводит «Успех». О втором вопросе есть скрытая регистрация в макросе 'BOOST_CLASS_EXPORT_GUID'. – megabyte1024

+0

ответ на ваш вопрос - да. Ваш комментарий также разъясняет некоторые из моих проблем. Тем не менее, чтобы прояснить концепцию, не могли бы вы сообщить мне, что не так с моим примером? (последний фрагмент кода). – rahman

 Смежные вопросы

  • Нет связанных вопросов^_^