从接口序列化派生类

时间:2013-08-07 15:22:21

标签: c++ boost-serialization

新:我可以在access.hpp中使用它吗?

template<class Archive, class T>
inline void serialize_adl(Archive &, T &, const unsigned int);

这表明我可以定义一个不同的序列化,将对象作为参数。

这样的代码会在下面改变吗?

我认为我的问题是如何添加序列化方法 接口类,它将调用序列化方法 派生子类。

class Interface {
public:
    virtual void aVirtual() = 0;
private:
    friend class boost::serialization::access;
    template<class Archive, class T>
    void serialize_adl(Archive & ar, T & object, const unsigned int version)
    {
       // Would this work?????
       ar & object;
    }
};

template<class T>
class Derived : Interface {
public:
   Derived(T in) : m_data(in) {}
   virtual void aVirtual() { // Do something }
private:
    T m_data;
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
       ar & m_data;
    }
};

我目前从编译器中收到以下错误:

error C2039: 'serialize' : is not a member of 'Interface'

这是不寻常的,因为对象在智能指针内,所以它应该 知道它是什么类型:

std::unique_ptr<Interface> object = std::unique_ptr<Interface>(new Derived<int>(5));

因此,当我尝试序列化时:

archive >> *object;

因此我得到了错误。

3 个答案:

答案 0 :(得分:4)

这里有两个问题:

  1. 您正在序列化模板类。这不是问题,是的,您可以通过ADL侵入(成员serialize)或非侵入性(自由函数serialize)。正如文档(Serializing Templates)所述,shared_ptr<T>序列化的实现是非侵入式变体的一个很好的例子:


  2. 您正在通过多态指针序列化基类/派生类。对于序列化部分,这没什么特别的(你可以register_type或者你可以在派生的base_object<Interface>(this)函数中使用serialize

    然而,在反序列化方面,您需要预测通过多态指针序列化的可能具体实例类型的完整列表。 BOOST_EXPORT_CLASS宏是实现此目的的最简单方法。但是,您必须列出您希望支持的模板的具体实例:

    BOOST_CLASS_EXPORT(Derived<std::string>)
    BOOST_CLASS_EXPORT(Derived<double>)
    BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
    

    BOOST_CLASS_EXPORT_GUID(Derived<std::string>, "4ef5a3ff-168a-4242-846b-4886f48424b5")
    BOOST_CLASS_EXPORT_GUID(Derived<double>,      "d0ed9de6-584f-476d-9898-8234bcb4efdb")
    BOOST_CLASS_EXPORT_GUID(Derived<int>,         "505538f0-2dd1-43bd-92a2-506ed9659bbe") // include all subtypes we can expect in an input archive
    
  3. 情况的复杂性 - 以及混乱 - 源于您通过多态指针序列化派生的类模板。一切都在同一时间。但从概念上讲,两者都很容易解决。

      

    略有不相关,

         
        
    • 是的,您可以使用免费功能序列化,请参阅下面的第3个替代版本。尽管如此,它几乎没有收获,只需要m_data可以公开访问。
    •   
    • 请勿使用serialize_adl,因为它是一个实施细节
    •   

    以下是三个集成了所有内容的示例:

    1. Live On Coliru - 原始Interface*

    2. Live On Coliru - 与shared_ptr<Interface>相同

    3. Live On Coliru - 与非侵入式serialize功能相同

    4. 列出第一个样本

      #include <boost/serialization/serialization.hpp>
      #include <boost/serialization/base_object.hpp>
      #include <boost/serialization/export.hpp>
      #include <boost/archive/text_oarchive.hpp>
      #include <boost/archive/text_iarchive.hpp>
      #include <sstream>
      
      class Interface {
          public:
              virtual void aVirtual() = 0;
              virtual ~Interface() {}
          private:
              friend class boost::serialization::access;
              template<class Archive> void serialize(Archive&, unsigned) { }
      };
      
      BOOST_SERIALIZATION_ASSUME_ABSTRACT(Interface)
      
      template<class T>
      class Derived : public Interface {
          public:
              Derived(T in = 0) : m_data(in) {}
              virtual void aVirtual() { /*Do something*/ }
              T const& getData() const { return m_data; }
          private:
              T m_data;
              friend class boost::serialization::access;
              template<class Archive>
                  void serialize(Archive& ar, unsigned)
                  {
                      ar & boost::serialization::base_object<Interface>(*this);
                      //// alternatively, if you don't want to make the abstract base serializable:
                      // boost::serialization::void_cast_register<Derived, Interface>();
      
                      ar & m_data;
                  }
      };
      
      BOOST_CLASS_EXPORT(Derived<std::string>)
      BOOST_CLASS_EXPORT(Derived<double>)
      BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
      
      int main()
      {
          std::stringstream ss;
      
          {
              boost::archive::text_oarchive oa(ss);
      
              Interface* o = new Derived<int>(42);
              oa << o;
      
              delete o;
          }
      
          std::cout << "Serialized: '" << ss.str() << "'\n";
      
          {
              boost::archive::text_iarchive ia(ss);
      
              Interface* o = nullptr;
              ia >> o;
      
              if (auto p = dynamic_cast<Derived<int>*>(o))
                  std::cout << "Deserialized into Derived<int> with data: " << p->getData() << "\n";
      
              delete o;
          }
      }
      

      示例输出:

      Serialized: '22 serialization::archive 11 0 1 1 12 Derived<int> 1 0
      0 42
      '
      Deserialized into Derived<int> with data: 42
      

答案 1 :(得分:0)

嗯,也许这可以帮助你或我可能是错的;但是在c ++继承中,没有一种机制可以调用子类的方法,因为一个类可以有很多子类而超类没有子类的引用,因为多态函数从子类到超类而不是在模式中反向。因此,您可以在派生类之后调用超类的函数。

最好的问候。

答案 2 :(得分:-1)

您应该仅序列化派生对象。使用dynamic_cast进行类型转换

 class Interface { 
     virtual void f() = 0; 
 }; 

 template<class T> class Derived : public Interface {
     T m_data; void f(){}; 
 }; 

 Interface* object = new Derived<Type>();

 Derived<Type>* objectSer = dynamic_cast<Derived<Type>*>(object); 

 //serialization 
 std::ofstream ofs("filename"); 
 boost::archive::text_oarchive oa(ofs); oa << *objectSer;