如何从序列化数据中“序列化”派生类?

时间:2010-07-16 20:57:22

标签: c++ serialization

如何从序列化数据中“序列化”派生类?或许我应该说,有没有更好的方法将数据“反序列化”为派生类?

例如,假设你有一个纯虚基类(B),它由另外三个类X,Y和Z继承。而且,我们有一个方法serialize(),它将翻译X:B,Y :B和Z:B为序列化数据。

这样可以将套接字,命名管道等连接到远程进程。

我遇到的问题是,我们如何从序列化数据中创建适当的对象?

我能想到的唯一解决方案是在序列化数据中包含一个标识符,用于指示最终的派生对象类型。接收者首先从序列化数据中解析派生类型字段,然后使用switch语句(或某种类似逻辑)来调用相应的构造函数。

例如:

B deserialize( serial_data )
{
    parse the derived type from the serial_data

    switch (derived type)
        case X
            return X(serial_data)
        case Y
            return Y(serial_data)
        case Z
            return Z(serial_data)
}

因此,在学习派生对象类型之后,我们调用适当的派生类型构造函数。

然而,这感觉很尴尬和麻烦。我希望有一种更有说服力的方式来做到这一点。有吗?

2 个答案:

答案 0 :(得分:2)

事实上,这比称为Virtual Constructor的序列化更为普遍。

传统的方法是Factory,它基于ID返回正确的派生类型。有两种解决方案:

  • 你注意到的switch方法,虽然你需要在堆上分配
  • prototype方法

原型方法如下:

// Cloneability
class Base
{
public:
  virtual Base* clone() const = 0;
};

class Derived: public Base
{
public:
  virtual Derived* clone() const { return new Derived(*this); }
};

// Factory
class Factory
{
public:
  Base* get(std::string const& id) const;
  void set(std::string const& id, Base* exemplar);

private:
  typedef std::map < std::string, Base* > exemplars_type;
  exemplars_type mExemplars;
};

Factory成为单身人士有点传统,但这完全是另一回事。

对于正确的反序列化,如果您有一个虚拟方法deserialize来调用该对象,则会更容易。

编辑:工厂如何运作?

在C ++中,您无法创建您不知道的类型。因此,上面的想法是通过Derived方法将Derived对象的构建任务赋予clone类。

接下来是Factory。我们将使用map将“标记”(例如"Derived")与对象的实例相关联(例如,此处为Derived)。

Factory factory;
Derived derived;
factory.set("Derived", &derived);

现在,当我们想要在编译时创建一个我们不知道的类型的对象时(因为类型是动态决定的),我们将标签传递给工厂并要求返回一个对象。

std::unique_ptr<Base> base = factory.get("Derived");

在封面下,Factory会找到与Base*代码相关联的"Derived",并调用该对象的clone方法。这实际上(这里)创建了一个运行时类型为Derived的对象。

我们可以使用typeid运算符验证这一点:

assert( typeid(base) == typeid(Derived) );

答案 1 :(得分:0)

inmemory:
--------
type1 {
  chartype a;
  inttype b;
};
serialize(new type1());

serialized(ignore { and ,):
---------------------------
type1id,len{chartypeid,adata,inttypeid,bdata}
我猜,在理想的序列化协议中,每个非基本类型都需要以typeid,len为前缀。即使你序列化了一个不是从任何东西派生的单一类型,你也会添加一个类型id,因为另一端必须知道它获取的类型(无论继承结构如何)。所以你必须在序列化中提到派生类id,因为从逻辑上讲它们是不同的类型。如果我错了,请纠正我。