11.4. 对象类层次结构的序列化

为了序列化基于类层次结构的对象,子类必须在 serialize ()函数中访问 boost::serialization::base_object ()。 此函数确保继承自基类的属性也能正确地序列化。 下面的例子演示了一个名为 developer 类,它继承自类 person

  1. #include <boost/archive/text_oarchive.hpp>
  2. #include <boost/archive/text_iarchive.hpp>
  3. #include <boost/serialization/string.hpp>
  4. #include <iostream>
  5. #include <sstream>
  6. #include <string>
  7.  
  8. std::stringstream ss;
  9.  
  10. class person
  11. {
  12. public:
  13. person()
  14. {
  15. }
  16.  
  17. person(int age)
  18. : age_(age)
  19. {
  20. }
  21.  
  22. int age() const
  23. {
  24. return age_;
  25. }
  26.  
  27. private:
  28. friend class boost::serialization::access;
  29.  
  30. template <typename Archive>
  31. void serialize(Archive &ar, const unsigned int version)
  32. {
  33. ar & age_;
  34. }
  35.  
  36. int age_;
  37. };
  38.  
  39. class developer
  40. : public person
  41. {
  42. public:
  43. developer()
  44. {
  45. }
  46.  
  47. developer(int age, const std::string &language)
  48. : person(age), language_(language)
  49. {
  50. }
  51.  
  52. std::string language() const
  53. {
  54. return language_;
  55. }
  56.  
  57. private:
  58. friend class boost::serialization::access;
  59.  
  60. template <typename Archive>
  61. void serialize(Archive &ar, const unsigned int version)
  62. {
  63. ar & boost::serialization::base_object<person>(*this);
  64. ar & language_;
  65. }
  66.  
  67. std::string language_;
  68. };
  69.  
  70. void save()
  71. {
  72. boost::archive::text_oarchive oa(ss);
  73. developer d(31, "C++");
  74. oa << d;
  75. }
  76.  
  77. void load()
  78. {
  79. boost::archive::text_iarchive ia(ss);
  80. developer d;
  81. ia >> d;
  82. std::cout << d.age() << std::endl;
  83. std::cout << d.language() << std::endl;
  84. }
  85.  
  86. int main()
  87. {
  88. save();
  89. load();
  90. }
  91.  

person developer 这两个类都包含有一个私有的 serialize () 函数, 它使得基于其他类的对象能被序列化。 由于 developer 类继承自 person 类, 所以它的 serialize () 函数必须确保继承自 person 属性也能被序列化。

继承自基类的属性被序列化是通过在子类的 serialize () 函数中用 boost::serialization::base_object () 函数访问基类实现的。 在例子中强制要求使用这个函数而不是 static_cast 是因为只有 boost::serialization::base_object () 才能保证正确地序列化。

动态创建对象的地址可以被赋值给对应的基类类型的指针。 下面的例子演示了 Boost.Serialization 还能够正确地序列化它们。

  1. #include <boost/archive/text_oarchive.hpp>
  2. #include <boost/archive/text_iarchive.hpp>
  3. #include <boost/serialization/string.hpp>
  4. #include <boost/serialization/export.hpp>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <string>
  8.  
  9. std::stringstream ss;
  10.  
  11. class person
  12. {
  13. public:
  14. person()
  15. {
  16. }
  17.  
  18. person(int age)
  19. : age_(age)
  20. {
  21. }
  22.  
  23. virtual int age() const
  24. {
  25. return age_;
  26. }
  27.  
  28. private:
  29. friend class boost::serialization::access;
  30.  
  31. template <typename Archive>
  32. void serialize(Archive &ar, const unsigned int version)
  33. {
  34. ar & age_;
  35. }
  36.  
  37. int age_;
  38. };
  39.  
  40. class developer
  41. : public person
  42. {
  43. public:
  44. developer()
  45. {
  46. }
  47.  
  48. developer(int age, const std::string &language)
  49. : person(age), language_(language)
  50. {
  51. }
  52.  
  53. std::string language() const
  54. {
  55. return language_;
  56. }
  57.  
  58. private:
  59. friend class boost::serialization::access;
  60.  
  61. template <typename Archive>
  62. void serialize(Archive &ar, const unsigned int version)
  63. {
  64. ar & boost::serialization::base_object<person>(*this);
  65. ar & language_;
  66. }
  67.  
  68. std::string language_;
  69. };
  70.  
  71. BOOST_CLASS_EXPORT(developer)
  72.  
  73. void save()
  74. {
  75. boost::archive::text_oarchive oa(ss);
  76. person *p = new developer(31, "C++");
  77. oa << p;
  78. delete p;
  79. }
  80.  
  81. void load()
  82. {
  83. boost::archive::text_iarchive ia(ss);
  84. person *p;
  85. ia >> p;
  86. std::cout << p->age() << std::endl;
  87. delete p;
  88. }
  89.  
  90. int main()
  91. {
  92. save();
  93. load();
  94. }
  95.  

应用程序在 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 为这种情况提供一种解决方案。

  1. #include <boost/archive/text_oarchive.hpp>
  2. #include <boost/archive/text_iarchive.hpp>
  3. #include <boost/serialization/string.hpp>
  4. #include <boost/serialization/export.hpp>
  5. #include <iostream>
  6. #include <sstream>
  7. #include <string>
  8.  
  9. std::stringstream ss;
  10.  
  11. class person
  12. {
  13. public:
  14. person()
  15. {
  16. }
  17.  
  18. person(int age)
  19. : age_(age)
  20. {
  21. }
  22.  
  23. virtual int age() const
  24. {
  25. return age_;
  26. }
  27.  
  28. private:
  29. friend class boost::serialization::access;
  30.  
  31. template <typename Archive>
  32. void serialize(Archive &ar, const unsigned int version)
  33. {
  34. ar & age_;
  35. }
  36.  
  37. int age_;
  38. };
  39.  
  40. class developer
  41. : public person
  42. {
  43. public:
  44. developer()
  45. {
  46. }
  47.  
  48. developer(int age, const std::string &language)
  49. : person(age), language_(language)
  50. {
  51. }
  52.  
  53. std::string language() const
  54. {
  55. return language_;
  56. }
  57.  
  58. private:
  59. friend class boost::serialization::access;
  60.  
  61. template <typename Archive>
  62. void serialize(Archive &ar, const unsigned int version)
  63. {
  64. ar & boost::serialization::base_object<person>(*this);
  65. ar & language_;
  66. }
  67.  
  68. std::string language_;
  69. };
  70.  
  71. void save()
  72. {
  73. boost::archive::text_oarchive oa(ss);
  74. oa.register_type<developer>();
  75. person *p = new developer(31, "C++");
  76. oa << p;
  77. delete p;
  78. }
  79.  
  80. void load()
  81. {
  82. boost::archive::text_iarchive ia(ss);
  83. ia.register_type<developer>();
  84. person *p;
  85. ia >> p;
  86. std::cout << p->age() << std::endl;
  87. delete p;
  88. }
  89.  
  90. int main()
  91. {
  92. save();
  93. load();
  94. }
  95.  

上面的应用程序没有使用 BOOST_CLASS_EXPORT 宏,而是调用了 register_type () 模板函数。 需要注册的类型作为模板参数传入。

请注意 register_type () 必须在 save ()load () 都要调用。

register_type () 的优点是只有需要序列化的类才注册。 比如在开发一个库时,你不知道开发人员将来要序列化哪些类。 当然 BOOST_CLASS_EXPORT 宏用起来简单,可它却可能注册那些不需要序列化的类型。