Common confusions with serializing polymorphic types

后端 未结 2 1012
南旧
南旧 2021-01-20 08:02

I have seen many questions, tutorials, and documentation involving serializing derived classes, and I haven\'t been able to reach a consensus on several issues, including (a

2条回答
  •  囚心锁ツ
    2021-01-20 08:16

    Following @sehe's advice, here are some example uses:

    Serialize derived class object, not forwarding to parent

    #include 
    #include 
    
    #include 
    
    class AbstractPoint
    {
    public:
        virtual ~AbstractPoint(){}
        virtual void DoSomething() = 0;
    };
    
    class Point : public AbstractPoint
    {
    public:
        Point() = default;
        Point(const double data) : mData(data) {}
    
        void DoSomething(){}
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            archive & mData;
        }
    
        double mData;
    };
    
    int main()
    {
        Point point(7.4);
    
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);
        outputArchive << point;
        outputStream.close();
    
        Point pointRead;
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        inputArchive >> pointRead;
    
        std::cout << pointRead.mData << std::endl;
        return 0;
    }
    

    Serialize derived class object, including (automatic) forwarding to parent:

    #include 
    #include 
    
    #include 
    
    class AbstractPoint
    {
    public:
        virtual ~AbstractPoint(){}
        virtual void DoSomething() = 0;
    
        double mParentData = 3.1;
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            archive & mParentData;
        }
    };
    
    class Point : public AbstractPoint
    {
    public:
        Point() = default;
        Point(const double data) : mData(data) {}
    
        void DoSomething(){}
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            // this is not required, the parent serialize() seems to be called automatically
            // archive & boost::serialization::base_object(*this);
    
            archive & mData;
        }
    
        double mData;
    };
    
    int main()
    {
        Point point(7.4);
    
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);
        outputArchive << point;
        outputStream.close();
    
        Point pointRead;
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        inputArchive >> pointRead;
    
        std::cout << pointRead.mParentData << std::endl;
        std::cout << pointRead.mData << std::endl;
        return 0;
    }
    

    Serialize derived class pointer, not forwarding to parent (note nothing changes from the object case)

    #include 
    #include 
    #include 
    
    #include 
    
    class AbstractPoint
    {
    public:
        virtual ~AbstractPoint(){}
        virtual void DoSomething() = 0;
    };
    
    class Point : public AbstractPoint
    {
    public:
        Point() = default;
        Point(const double data) : mData(data) {}
    
        void DoSomething(){}
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            archive & mData;
        }
    
        double mData;
    };
    
    int main()
    {
        std::shared_ptr point(new Point(7.4));
    
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);
        outputArchive << point;
        outputStream.close();
    
        std::shared_ptr pointRead;
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        inputArchive >> pointRead;
    
        std::cout << pointRead->mData << std::endl;
        return 0;
    }
    

    Serialize derived class pointer, forwarding to parent (note nothing changes from the object case)

    #include 
    #include 
    #include 
    
    #include 
    
    class AbstractPoint
    {
    public:
        virtual ~AbstractPoint(){}
        virtual void DoSomething() = 0;
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            archive & mParentData;
        }
    
        double mParentData = 3.1;
    };
    
    class Point : public AbstractPoint
    {
    public:
        Point() = default;
        Point(const double data) : mData(data) {}
    
        void DoSomething(){}
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            archive & mData;
        }
    
        double mData;
    };
    
    int main()
    {
        std::shared_ptr point(new Point(7.4));
    
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);
        outputArchive << point;
        outputStream.close();
    
        std::shared_ptr pointRead;
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        inputArchive >> pointRead;
    
        std::cout << pointRead->mParentData << std::endl;
        std::cout << pointRead->mData << std::endl;
        return 0;
    }
    

    Serialize base class pointer (We now have to register the type of the derived class with the archives, as well as use boost::serialization::base_object)

    #include 
    #include 
    #include 
    #include 
    
    #include 
    
    class AbstractPoint
    {
    public:
        virtual ~AbstractPoint(){}
        virtual void DoSomething() = 0;
    
        // This is required if we want to serialize an AbstractPoint pointer
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            // do nothing
        }
    };
    
    class Point : public AbstractPoint
    {
    public:
        Point() = default;
        Point(const double data) : mData(data) {}
    
        void DoSomething(){}
    
        template
        void serialize(TArchive& archive, const unsigned int version)
        {
            // Without this, we get unregistered void cast
            archive & boost::serialization::base_object(*this);
    
            archive & mData;
        }
    
        double mData;
    };
    
    int main()
    {
        std::shared_ptr point(new Point(7.4));
    
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);
        outputArchive.register_type();
        outputArchive << point;
        outputStream.close();
    
        std::shared_ptr pointRead;
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        inputArchive.register_type();
        inputArchive >> pointRead;
    
        std::shared_ptr castedPoint = std::dynamic_pointer_cast(pointRead);
        std::cout << castedPoint->mData << std::endl;
        return 0;
    }
    

提交回复
热议问题