从接口序列化派生类

Serializing a derived class from an interface

本文关键字:派生 序列化 接口      更新时间:2023-10-16

新建:我可以从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;

因此我得到了错误。

这里有两个问题:

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

    • http://www.boost.org/doc/libs/release/boost/serialization/shared_ptr.hpp


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

    然而,在反序列化方面,您需要预测通过多态指针序列化的可能的具体实例类型的完整列表。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
    

这种情况的复杂性和混乱源于您正在通过多态指针序列化派生的类模板。所有这些同时发生。但从概念上讲,两者都很容易解决。

稍不相关,

  • 是的,您可以使用免费的函数序列化,请参阅下面的第三个替代版本。不过,它并没有给你带来什么好处,只是要求m_data可以公开访问
  • 不要使用serialize_adl,因为它是一个实现细节

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

  1. 在Coliru上直播 -原始Interface*

  2. 在Coliru上直播 -与shared_ptr<Interface> 相同

  3. 在Coliru上直播 -与非侵入式serialize功能相同

第一个示例的列表

#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

好吧,也许这对你有帮助,或者我可能错了;但是在c++inherit中,没有一个机制可以调用子类的方法,因为一个类可以有很多子类,而超类没有子类的引用,因为从子类到超类的多态性函数是不可逆的。因此,可以从派生类开始调用超类的函数。

致以最良好的问候。

您应该只序列化派生对象。使用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;