11.4. 对象类层次结构的序列化
为了序列化基于类层次结构的对象,子类必须在 serialize ()
函数中访问 boost::serialization::base_object ()
。 此函数确保继承自基类的属性也能正确地序列化。 下面的例子演示了一个名为 developer
类,它继承自类 person
。
- #include <boost/archive/text_oarchive.hpp>
- #include <boost/archive/text_iarchive.hpp>
- #include <boost/serialization/string.hpp>
- #include <iostream>
- #include <sstream>
- #include <string>
- std::stringstream ss;
- class person
- {
- public:
- person()
- {
- }
- person(int age)
- : age_(age)
- {
- }
- int age() const
- {
- return age_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & age_;
- }
- int age_;
- };
- class developer
- : public person
- {
- public:
- developer()
- {
- }
- developer(int age, const std::string &language)
- : person(age), language_(language)
- {
- }
- std::string language() const
- {
- return language_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object<person>(*this);
- ar & language_;
- }
- std::string language_;
- };
- void save()
- {
- boost::archive::text_oarchive oa(ss);
- developer d(31, "C++");
- oa << d;
- }
- void load()
- {
- boost::archive::text_iarchive ia(ss);
- developer d;
- ia >> d;
- std::cout << d.age() << std::endl;
- std::cout << d.language() << std::endl;
- }
- int main()
- {
- save();
- load();
- }
person
和 developer
这两个类都包含有一个私有的 serialize ()
函数, 它使得基于其他类的对象能被序列化。 由于 developer
类继承自 person
类, 所以它的 serialize ()
函数必须确保继承自 person
属性也能被序列化。
继承自基类的属性被序列化是通过在子类的 serialize ()
函数中用 boost::serialization::base_object ()
函数访问基类实现的。 在例子中强制要求使用这个函数而不是 static_cast
是因为只有 boost::serialization::base_object ()
才能保证正确地序列化。
动态创建对象的地址可以被赋值给对应的基类类型的指针。 下面的例子演示了 Boost.Serialization 还能够正确地序列化它们。
- #include <boost/archive/text_oarchive.hpp>
- #include <boost/archive/text_iarchive.hpp>
- #include <boost/serialization/string.hpp>
- #include <boost/serialization/export.hpp>
- #include <iostream>
- #include <sstream>
- #include <string>
- std::stringstream ss;
- class person
- {
- public:
- person()
- {
- }
- person(int age)
- : age_(age)
- {
- }
- virtual int age() const
- {
- return age_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & age_;
- }
- int age_;
- };
- class developer
- : public person
- {
- public:
- developer()
- {
- }
- developer(int age, const std::string &language)
- : person(age), language_(language)
- {
- }
- std::string language() const
- {
- return language_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object<person>(*this);
- ar & language_;
- }
- std::string language_;
- };
- BOOST_CLASS_EXPORT(developer)
- void save()
- {
- boost::archive::text_oarchive oa(ss);
- person *p = new developer(31, "C++");
- oa << p;
- delete p;
- }
- void load()
- {
- boost::archive::text_iarchive ia(ss);
- person *p;
- ia >> p;
- std::cout << p->age() << std::endl;
- delete p;
- }
- int main()
- {
- save();
- load();
- }
应用程序在 save ()
函数创建了 developer
类型的对象并赋值给 person*
类型的指针,接下来通过 <<
序列化。
正如在前面章节中提到的, 引用对象被自动地序列化。 为了让 Boost.Serialization 识别将要序列化的 developer
类型的对象,即使指针是 person*
类型的对象。 developer
类需要相应的声明。 这是通过这个 BOOST_CLASS_EXPORT
宏实现的,它定义在 boost/serialization/export.hpp
文件中。 因为 developer
这个数据类型没有指针形式的定义,所以 Boost.Serialization 没有这个宏就不能正确地序列化 developer
。
如果子类对象需要通过基类的指针序列化,那么 BOOST_CLASS_EXPORT
宏必须要用。
由于静态注册的原因, BOOST_CLASS_EXPORT
的一个缺点是可能有些注册的类最后是不需要序列化的。 Boost.Serialization 为这种情况提供一种解决方案。
- #include <boost/archive/text_oarchive.hpp>
- #include <boost/archive/text_iarchive.hpp>
- #include <boost/serialization/string.hpp>
- #include <boost/serialization/export.hpp>
- #include <iostream>
- #include <sstream>
- #include <string>
- std::stringstream ss;
- class person
- {
- public:
- person()
- {
- }
- person(int age)
- : age_(age)
- {
- }
- virtual int age() const
- {
- return age_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & age_;
- }
- int age_;
- };
- class developer
- : public person
- {
- public:
- developer()
- {
- }
- developer(int age, const std::string &language)
- : person(age), language_(language)
- {
- }
- std::string language() const
- {
- return language_;
- }
- private:
- friend class boost::serialization::access;
- template <typename Archive>
- void serialize(Archive &ar, const unsigned int version)
- {
- ar & boost::serialization::base_object<person>(*this);
- ar & language_;
- }
- std::string language_;
- };
- void save()
- {
- boost::archive::text_oarchive oa(ss);
- oa.register_type<developer>();
- person *p = new developer(31, "C++");
- oa << p;
- delete p;
- }
- void load()
- {
- boost::archive::text_iarchive ia(ss);
- ia.register_type<developer>();
- person *p;
- ia >> p;
- std::cout << p->age() << std::endl;
- delete p;
- }
- int main()
- {
- save();
- load();
- }
上面的应用程序没有使用 BOOST_CLASS_EXPORT
宏,而是调用了 register_type ()
模板函数。 需要注册的类型作为模板参数传入。
请注意 register_type ()
必须在 save ()
和 load ()
都要调用。
register_type ()
的优点是只有需要序列化的类才注册。 比如在开发一个库时,你不知道开发人员将来要序列化哪些类。 当然 BOOST_CLASS_EXPORT
宏用起来简单,可它却可能注册那些不需要序列化的类型。