C / C ++:序列化方法应该是类成员吗?

时间:2014-09-14 17:54:36

标签: c++ class serialization polymorphism

假设我们有一个复杂的(即非原始的)类ComplexObject定义如下:

class A{...};

class B{...};

class C{...};

class ComplexObject
{
private:
    A _fieldA;
    B _fieldB;
    C _fieldC;
};

我想实现一个序列化程序,将ComplexObject的实例序列化为二进制形式。根据我在C#中的经验,我已经看到了实现序列化器的3种不同方法。

  1. serialize(binarystream&)的定义中定义ComplexObject方法以及" child"课程,ABCserialize中定义的ComplexObject方法将以递归方式调用子成员的方法。
  2. 创建一个单独的类,其中包含序列化ComplexObjectABC的方法。用于序列化ComplexObject的方法将以递归方式调用子成员的方法。当然,必须在类中定义getter以检索序列化程序的私有字段。
  3. 使用反射生成对象的模板,并根据生成的模板将所有可序列化的字段写入表中。
  4. 不幸的是,我相信在C ++中使用反射将非常困难,所以我将远离第三种选择。我已经看到选项1和2都经常使用(在C#中)。

    选项1对选项2的优势在于它允许通过将ComplexObject方法标记为虚拟来从serilalize(binarystream&)派生的类。但是,它会添加到对象的成员函数列表中并使程序员感到困惑。您没有在serialize中看到std::string方法定义,是吗?

    另一方面,选项2取出并将所有序列化方法组合在一起,使事情变得更整洁。但是,我认为它不容易适应ComplexObject的派生类。

    在哪种情况下应该使用每个选项(1和2)?

3 个答案:

答案 0 :(得分:1)

我选择"两者"。序列化具有对象中的组件和(模板化的)独立功能。

例如:

class Serialization_Interface
{
  public:
    virtual void load_from_buffer(uint8_t*& buffer_ptr) = 0;
};

void Load_From_Buffer(unsigned int& number, uint8_t*& buffer_pointer)
{
  number = *((unsigned int *) buffer_ptr);
  buffer_pointer += sizeof(unsigned int);
}

template <class Object>
void Load_From_Buffer(Object& obj, uint8_t*& buffer_pointer)
{
  obj.load_from_buffer(buffer_pointer);
}

不要将自己限制在两个选择范围内。总是第三种选择。 : - )

另外,不要重新发明轮子,请查看Boost :: serialization。

答案 1 :(得分:1)

C ++没有反射,但这并不意味着序列化代码需要手工编写。

您可以使用代码生成器(例如,协议缓冲区)从简单描述创建序列化代码。当然,该描述格式不支持用于创建公共API的丰富C ++功能,但是您可以采用由代码生成器创建的数据结构类型并将其嵌入到您的“真实”中。类,直接嵌入或通过pimpl。这样你就可以在你的类中编写所有非序列化行为,但它没有自己的任何数据,它依赖于序列化对象来存储数据。

它基本上与您的方法#2相似,但应用控制反转。序列化程序逻辑无法访问您的类以访问数据,而是负责将数据存储在您的类也可以使用它的位置。

答案 2 :(得分:0)

我不会为使用自制的序列化器而烦恼。 (请注意,设计反序列化比序列化更难......) 我宁愿使用一些东西:

https://code.google.com/p/protobuf/

http://android-developers.blogspot.com/2014/06/flatbuffers-memory-efficient.html

或提升(您还可以查看他们如何解决类似问题) http://www.boost.org/doc/libs/1_56_0/libs/serialization/doc/index.html

回到你的困境。 将所有序列化代码分组到一个类中是一个坏主意,因为这个类会随着每个新的可序列化对象而增长。您可以为每个“可序列化”类使用朋友“序列化程序”类, 或使用朋友方法/运营商&lt;&lt;。 但是没有完美的解决方案,这不是一件容易的事。如果可以,请使用lib。