使用Boost将派生类部分反序列化为基类时输入流错误

Posted

技术标签:

【中文标题】使用Boost将派生类部分反序列化为基类时输入流错误【英文标题】:Input stream error when partially deserializing derived class into base class using Boost 【发布时间】:2016-02-02 13:22:57 【问题描述】:

当我使用 boost 序列化派生类并尝试仅反序列化基本部分时,我收到输入流错误。我想我的代码是错误的。有没有办法使用 boost 存档仅反序列化派生对象的基本部分? 这段代码的原因是我正在尝试实现一种将派生对象从一个进程发送到另一个进程的设计。接收进程会查看基础部分中的 ID 来决定接收哪个派生对象。

这是我试图验证使用 boost 是否可行的测试代码,但执行此操作时出现输入流错误

class DataIface

 public:
DataIface()
:num(0)


DataIface( int num):
    num(num)


int num;
template< class Archive >
    void serialize( Archive& ar, const unsigned int version )
    
        std::cout<<"Serializing base class \n"<<std::endl;
        ar & num;
    
;

class Data1 : public DataIface

private:
friend class boost::serialization::access;
public:
Data1()
:a(0)


;
Data1( int a, int num):
    DataIface(num),
    a(a)



int a;
template< class Archive >
void serialize( Archive& ar, const unsigned int version )

    std::cout<<"Serializing derived class \n"<<std::endl;
    ar & boost::serialization::base_object<DataIface>(*this);
    ar & a;



;

int main()

Data1 obj(10, 20);
std::ostringstream oss;
boost::archive::text_oarchive oa( oss );

oa << obj;

Data1 obj2;

std::istringstream iss(oss.str());
boost::archive::text_iarchive ia( iss );

ia >> obj2;

cout<< obj2.a << std::endl;
cout << obj2.num << std::endl;

DataIface iface;
try

 ia >> iface;

catch(std::exception& e)

    std::cout<<e.what()<<std::endl;

cout << iface.num << std::endl;



return 0;

任何帮助将不胜感激

【问题讨论】:

【参考方案1】:

这是我正在尝试验证是否可以使用 boost 的测试代码,但出现输入流错误

结论是什么?

结论是:它不起作用。那是因为它不是一个功能。文档中的任何地方都没有建议您可以这样做。

运行时多态

按预期使用多态!

Live On Coliru

#include <iostream>
#include <sstream>

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

class DataIface 
  public:
    virtual ~DataIface() 
    template <class Archive> void serialize(Archive &ar, const unsigned int version) 
        std::cout << __PRETTY_FUNCTION__ << "\n";
    
;

class Data1 : public DataIface 
    friend class boost::serialization::access;

  public:
    Data1(int a=0) : a(a) 
    int a;
    template <class Archive> void serialize(Archive &ar, const unsigned int version) 
        std::cout << __PRETTY_FUNCTION__ << "\n";
        ar &boost::serialization::base_object<DataIface>(*this);
        ar &a;
    
;

class Data2 : public DataIface 
    friend class boost::serialization::access;

  public:
    Data2(int b=0) : b(b) 
    int b;
    template <class Archive> void serialize(Archive &ar, const unsigned int version) 
        std::cout << __PRETTY_FUNCTION__ << "\n";
        ar &boost::serialization::base_object<DataIface>(*this);
        ar &b;
    
;


BOOST_CLASS_EXPORT(Data1)
BOOST_CLASS_EXPORT(Data2)

int main() 

    DataIface* tests[] =  new Data1(10), new Data2(-10) ;

    for(auto testobj : tests)
    
        std::ostringstream oss;
        
            boost::archive::text_oarchive oa(oss);

            oa << testobj;
        

        
            std::istringstream iss(oss.str());
            boost::archive::text_iarchive ia(iss);

            DataIface* obj = nullptr;
            ia >> obj;

            if (Data1* obj1 = dynamic_cast<Data1*>(obj))
                std::cout << "It's a Data1: " << obj1->a << "\n";
            if (Data2* obj2 = dynamic_cast<Data2*>(obj))
                std::cout << "It's a Data2: " << obj2->b << "\n";
        
    

    for(auto ptr : tests) delete ptr;

打印:

void Data1::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void Data1::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
It's a Data1: 10
void Data2::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_oarchive]
void Data2::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
void DataIface::serialize(Archive&, unsigned int) [with Archive = boost::archive::text_iarchive]
It's a Data2: -10

静态多态

或者,使用变体。这为您省去了手动动态分配的麻烦和虚拟调度的潜在成本。

Live On Coliru

#include <iostream>
#include <sstream>

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

class Data1 
    friend class boost::serialization::access;

  public:
    Data1(int a=0) : a(a) 
    int a;
    template <class Archive> void serialize(Archive &ar, const unsigned int version) 
        ar &a;
    

    friend std::ostream& operator<<(std::ostream& os, Data1 const& d) 
        return os << "It's a Data1: " << d.a;
    
;

class Data2 
    friend class boost::serialization::access;

  public:
    Data2(int b=0) : b(b) 
    int b;
    template <class Archive> void serialize(Archive &ar, const unsigned int version) 
        ar &b;
    

    friend std::ostream& operator<<(std::ostream& os, Data2 const& d) 
        return os << "It's a Data2: " << d.b;
    
;

int main() 

    using V = boost::variant<Data1, Data2>;
    V tests[] =  Data110, Data2-10 ;

    for(auto testobj : tests)
    
        std::ostringstream oss;
        
            boost::archive::text_oarchive oa(oss);
            oa << testobj;
        

        
            std::istringstream iss(oss.str());
            boost::archive::text_iarchive ia(iss);

            V deserialized;
            ia >> deserialized;

            std::cout << deserialized << "\n";
        
    

打印出来:

It's a Data1: 10
It's a Data2: -10

【讨论】:

以上是关于使用Boost将派生类部分反序列化为基类时输入流错误的主要内容,如果未能解决你的问题,请参考以下文章

在 Boost (C++) 中没有类跟踪的派生类序列化

序列化派生类时不包括 ProtoBuf.net 基类属性

将xml反序列化为c#中的类时从XmlTextAttribute获取int值

protobuf-net 序列化为基类

boost::serialization 用基类指针转存派生类(错误多多,一波三折)

BOOST_CLASS_EXPORT