c++ - 你如何从序列化数据中获取 'de-serialize' 的派生类?

标签 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)
}

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

但是,这感觉很尴尬和麻烦。我希望有一种更 Eloquent 方式来做到这一点。有吗?

最佳答案

事实上,这是一个比称为 Virtual Constructor 的序列化更普遍的问题.

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

  • switch您注意到的方法,尽管您需要在堆上分配
  • prototype方法

原型(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 来验证这一点运算符(operator):

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

关于c++ - 你如何从序列化数据中获取 'de-serialize' 的派生类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3268801/

相关文章:

asp.net-core - 用于 net core 3.1 Web Api 问题的自定义 OData 格式化程序

c++ - 在多线程应用程序中等待变量的最佳方法是什么

c++ - 在 C++11 中使用 SFINAE 在具有相同签名的两个函数之间进行选择

c# - 如何制作 PInvoke 友好的 native API?

C++ 猜谜游戏 : unable to get midpoint properly

c# - Cinchoo ETL 将类序列化为 csv

c++ - 头文件和 cpp 文件中的运算符重载

java - 如何使用 org.apache.commons.codec.binary.base64 对 Java 对象进行 Base64 编码?

c++ - 在文件中维护链表

c# - 序列化对于对象大小估计可靠吗?