类层次结构对象的序列化
派生类必须访问成员函数 serialize() 中的函数 boost::serialization::base_object() 以根据类层次结构序列化对象。该函数保证基类的继承成员变量被正确序列化。
示例 64.11。正确序列化派生类
- #include
- #include
- #include
- #include
-
- using namespace boost::archive;
- std::stringstream ss;
-
- class animal
- {
- public:
- animal() = default;
- animal(int legs) : legs_{legs} {}
- int legs() const { return legs_; }
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version) { ar & legs_; }
-
- int legs_;
- };
-
- class bird : public animal
- {
- public:
- bird() = default;
- bird(int legs, bool can_fly) :
- animal{legs}, can_fly_{can_fly} {}
- bool can_fly() const { return can_fly_; }
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object
(*this); - ar & can_fly_;
- }
-
- bool can_fly_;
- };
-
- void save()
- {
- text_oarchive oa{ss};
- bird penguin{2, false};
- oa << penguin;
- }
-
- void load()
- {
- text_iarchive ia{ss};
- bird penguin;
- ia >> penguin;
- std::cout << penguin.legs() << '\n';
- std::cout << std::boolalpha << penguin.can_fly() << '\n';
- }
-
- int main()
- {
- save();
- load();
- }
示例 64.11 使用了一个名为 bird 的类,它派生自 animal。 animal 和 bird 都定义了一个私有成员函数 serialize() ,这使得序列化基于任一类的对象成为可能。因为 bird 派生自 animal,serialize() 必须确保从 animal 继承的成员变量也被序列化。
通过在派生类的成员函数 serialize() 中访问基类并调用 boost::serialization::base_object() 来序列化继承的成员变量。您必须使用此函数而不是,例如,static_cast,因为只有 boost::serialization::base_object() 才能确保正确的序列化。
动态创建对象的地址可以分配给相应基类类型的指针。示例 64.12 表明 Boost.Serialization 也可以正确地序列化它们。
示例 64.12。使用 BOOST_CLASS_EXPORT 静态注册派生类
- #include
- #include
- #include
- #include
- #include
-
- using namespace boost::archive;
-
- std::stringstream ss;
-
- class animal
- {
- public:
- animal() = default;
- animal(int legs) : legs_{legs} {}
- virtual int legs() const { return legs_; }
- virtual ~animal() = default;
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version) { ar & legs_; }
-
- int legs_;
- };
-
- class bird : public animal
- {
- public:
- bird() = default;
- bird(int legs, bool can_fly) :
- animal{legs}, can_fly_{can_fly} {}
- bool can_fly() const { return can_fly_; }
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object
(*this); - ar & can_fly_;
- }
-
- bool can_fly_;
- };
-
- BOOST_CLASS_EXPORT(bird)
-
- void save()
- {
- text_oarchive oa{ss};
- animal *a = new bird{2, false};
- oa << a;
- delete a;
- }
-
- void load()
- {
- text_iarchive ia{ss};
- animal *a;
- ia >> a;
- std::cout << a->legs() << '\n';
- delete a;
- }
-
- int main()
- {
- save();
- load();
- }
该程序在函数 save() 中创建了一个 bird 类型的对象,并将其分配给一个 animal* 类型的指针,该指针又通过 operator<< 进行序列化。
上一节提到,被引用的对象被序列化,而不是指针。要让 Boost.Serialization 认识到必须序列化 bird 类型的对象,即使指针是 animal* 类型,也需要声明 bird 类。这是使用在 boost/serialization/export.hpp 中定义的宏 BOOST_CLASS_EXPORT 完成的。因为类型 bird 没有出现在指针定义中,Boost.Serialization 不能在没有宏的情况下正确序列化 bird 类型的对象。
如果要使用指向相应基类的指针对派生类的对象进行序列化,则必须使用宏 BOOST_CLASS_EXPORT。 BOOST_CLASS_EXPORT 的一个缺点是,由于静态注册,可以注册可能根本不用于序列化的类。 Boost.Serialization 为这种情况提供了解决方案。
示例 64.13。使用 register_type() 动态注册派生类
- #include
- #include
- #include
- #include
- #include
-
- std::stringstream ss;
-
- class animal
- {
- public:
- animal() = default;
- animal(int legs) : legs_{legs} {}
- virtual int legs() const { return legs_; }
- virtual ~animal() = default;
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version) { ar & legs_; }
-
- int legs_;
- };
-
- class bird : public animal
- {
- public:
- bird() = default;
- bird(int legs, bool can_fly) :
- animal{legs}, can_fly_{can_fly} {}
- bool can_fly() const { return can_fly_; }
-
- private:
- friend class boost::serialization::access;
-
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object
(*this); - ar & can_fly_;
- }
-
- bool can_fly_;
- };
-
- void save()
- {
- boost::archive::text_oarchive oa{ss};
- oa.register_type
(); - animal *a = new bird{2, false};
- oa << a;
- delete a;
- }
-
- void load()
- {
- boost::archive::text_iarchive ia{ss};
- ia.register_type
(); - animal *a;
- ia >> a;
- std::cout << a->legs() << '\n';
- delete a;
- }
-
- int main()
- {
- save();
- load();
- }
示例 64.13 不使用宏 BOOST_CLASS_EXPORT,而是调用成员函数模板 register_type()。要注册的类型作为模板参数传递。请注意,必须在 save() 和 load() 中调用 register_type()。
register_type() 的优点是只需要注册用于序列化的类。例如,在开发库时,不知道开发人员以后可能使用哪些类进行序列化。虽然宏 BOOST_CLASS_EXPORT 使这很容易,但它可能会注册不会用于序列化的类型。