促进多重继承的序列化

Boost serialization for multiple inheritance

考虑

class B;
class C;
class A: public  B, public  C
{
 int a;
 ...
}

这是正确的连载方式吗?

friend class  boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int ver)
{
    ar & boost::serialization::base_object<B>(*this);
    ar & boost::serialization::base_object<C>(*this);
    ar & a;
    ...
}

顺序重要吗(对于序列化和反序列化)?

什么是最好的在很大程度上取决于您打算做什么。在许多情况下,class 由继承组成的事实与序列化的相关实现细节无关,因此 "best" 实现很容易看起来像

template<class Archive>
void serialize(Archive & ar, unsigned) {
    ar & a;
}

但是,假设您在其他地方引用了 base-classes 并且您确实需要跟踪这些,那么您应该使用您拥有的内容,并进行一些修改以防您打算使用 XML 档案:

Live On Coliru

#include <boost/archive/xml_oarchive.hpp>
#include <boost/archive/xml_iarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/string.hpp>

class B {
    std::string name = "Thor";
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) { ar & BOOST_SERIALIZATION_NVP(name); }
};
class C {
    double trouble;
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) { ar & BOOST_SERIALIZATION_NVP(trouble); }
};

class A : public B, public C {
    int a = 42;

  private:
    friend class boost::serialization::access;

    template <class Archive> void serialize(Archive &ar, unsigned) {

        ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(B)
           & BOOST_SERIALIZATION_BASE_OBJECT_NVP(C)
           & BOOST_SERIALIZATION_NVP(a);
    }
};

struct Test {
    A derived;
    B* baseb = nullptr;
    C* basec = nullptr;
  private:
    friend class boost::serialization::access;
    template <class Archive> void serialize(Archive &ar, unsigned) {
        ar & BOOST_SERIALIZATION_NVP(derived)
           & BOOST_SERIALIZATION_NVP(baseb)
           & BOOST_SERIALIZATION_NVP(basec);
    }
};

#include <iostream>
#include <fstream>
int main(int argc, char**) {
    if (argc == 1) {
        std::ofstream ofs("test.xml");
        boost::archive::xml_oarchive oa(ofs);

        Test test;
        test.baseb = &test.derived; // for asserting below
        test.basec = &test.derived; // for asserting below
        oa << BOOST_SERIALIZATION_NVP(test);
    }

    std::cout << std::ifstream("test.xml").rdbuf();

    {
        std::ifstream ifs("test.xml");
        boost::archive::xml_iarchive ia(ifs);

        Test test;
        ia >> BOOST_SERIALIZATION_NVP(test);

        assert(static_cast<B*>(&test.derived) == test.baseb);
        assert(static_cast<C*>(&test.derived) == test.basec);
    }
}

顺序无关紧要(从技术上讲,构建步骤是分开的,发生在序列化函数运行之前)。但是,我个人会将基本序列化按声明顺序排列。

示例输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="16">
<test class_id="0" tracking_level="0" version="0">
    <derived class_id="1" tracking_level="0" version="0">
        <B class_id="2" tracking_level="1" version="0" object_id="_0">
            <name>Thor</name>
        </B>
        <C class_id="3" tracking_level="1" version="0" object_id="_1">
            <trouble>1.68426978667280947e-320</trouble>
        </C>
        <a>42</a>
    </derived>
    <baseb class_id_reference="2" object_id_reference="_0"></baseb>
    <basec class_id_reference="3" object_id_reference="_1"></basec>
</test>
</boost_serialization>

备注from the docs:

Resist the temptation to just cast *this to the base class. This might seem to work but may fail to invoke code necessary for proper serialization.

Note that this is NOT the same as calling the serialize function of the base class. This might seem to work but will circumvent certain code used for tracking of objects, and registering base-derived relationships and other bookkeeping that is required for the serialization system to function as designed.

For this reason, all serialize member functions should be private.