c++ - 正确的类型转换以 boost 不同派生类的反序列化

标签 c++ serialization boost boost-serialization

在我的应用程序中,有不同类型的代理。我打算使用 boost 序列化在代理之间发送/接收数据。(通过发送/接收,我实际上是指对序列化目标文件进行写入/读取操作)

接收代理可能会收到不同类型的数据,这些数据的类型是事先不知道的。假设数据格式具有如下一般结构:

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_oarchivexml_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;
}

旧对象和新对象不相等,因为再次将新对象保存(序列化)到另一个文件会导致不同的(空)内容。您能否告诉我如何修复此代码以成功反序列化派生类?非常感谢

EDIT-2 上面的代码现在没有任何问题(在修复了一个小错别字之后)。 我在这里回答我自己的问题,因为还有其他人建议的另一种好方法。 所以我的第一个问题的答案是这样的: 只要您在主序列化函数中注册派生类型(在上面的例子中:bus_route 类中的 serialize()),一切都应该没问题。

谢谢大家的帮助

最佳答案

解决方案是(反)序列化 boost::shared_ptr<Base> .下面的代码演示了它。反序列化后 pDstDerived_1 的一个实例类(class)。使用在线编译器编译的代码可在 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();
}

关于c++ - 正确的类型转换以 boost 不同派生类的反序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15237947/

相关文章:

c++ - 我怎么知道谁持有 shared_ptr<>?

c++ - C++中唯一锁、互斥量和条件变量的关系

c++ - 派生类和基类对象的内存地址?

java - 如何使用可序列化类

c# - 从数据库反序列化二进制数组 C#

c++ - 在没有虚拟原型(prototype)的情况下调用继承类的一种方法

c++ - Directx 位图无法加载

c++ - 将 `nullptr` 分配给 `bool` 类型。哪个编译器是正确的?

php - Symfony Serializer 无法在反序列化时处理 Doctrine Id

c++ - 覆盖专用模板