如何从序列化数据中“序列化”派生类?或许我应该说,有没有更好的方法将数据“反序列化”为派生类?
例如,假设你有一个纯虚基类(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)
}
因此,在学习派生对象类型之后,我们调用适当的派生类型构造函数。
然而,这感觉很尴尬和麻烦。我希望有一种更有说服力的方式来做到这一点。有吗?
答案 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,因为从逻辑上讲它们是不同的类型。如果我错了,请纠正我。