правильное приведение типов для ускоренной десериализации различных производных классов

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

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

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 {...};
};

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

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 к.
тогда как в моем случае, так как я знаю, что я отправляю, я могу сделать надлежащую регистрацию&сериализация на индивидуальной основе. Однако на принимающей стороне я заранее не знаю, что регистрировать и что динамически разыгрывать.

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

Спасибо

РЕДАКТИРОВАТЬ:
Вот упрощенная модификация 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;
}

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

РЕДАКТИРОВАТЬ-2
В приведенном выше коде нет ничего плохого (после небольшой опечатки).
Я отвечаю на свой вопрос здесь, потому что есть еще один хороший подход, предложенный кем-то еще.
Итак Ответ на мой первый вопрос так:
Пока вы регистрируете производные типы в основной функции сериализации (в приведенном выше случае: serialize () в классе bus_route), все должно быть хорошо.

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

2

Решение

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

#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();
}
2

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector