C++ 如何执行多态继承层次结构的灵活序列化?

C++ 如何执行多态继承层次结构的灵活序列化?,c++,serialization,C++,Serialization,我试图仔细阅读报告中关于这个问题的所有建议。我已经根据第36.8项实现了我的系统,几个月后(大量数据序列化),我想对一些类的公共接口和继承结构本身进行更改 class Base { public: Vector field1() const; Vector field2() const; Vector field3() const; std::string name() const {return "Base";} }; class Derived : public

我试图仔细阅读报告中关于这个问题的所有建议。我已经根据第36.8项实现了我的系统,几个月后(大量数据序列化),我想对一些类的公共接口和继承结构本身进行更改

class Base
{
public:
   Vector field1() const;
   Vector field2() const; 
   Vector field3() const;
   std::string name() const {return "Base";}
};

class Derived : public Base
{
public:
    std::string name() const {return "Derived";}
};
我想知道如何进行更改,例如:

  • 派生的
    拆分为
    派生的1
    派生的2
    ,同时将原始的
    派生的
    映射到现有数据的
    派生的1

  • Base::field1()
    拆分为
    Base::field1a()
    Base::field1b()
    ,同时将
    field1
    映射到
    field1a
    ,并使现有数据的
    field1b
    为空

  • 我不得不

  • 反序列化我的旧数据的所有千兆字节
  • 将它们转换为新的继承结构
  • 以一种新的更灵活的方式对其进行重新分类
  • 我想知道如何使序列化更加灵活,这样当我决定在将来进行一些更改时,我就不会像现在这样面临转换

    我想制作一个系统,使用数字而不是名称来序列化我的对象。例如Base=1,Derived1=2。。。还有一个单独的数字到名称的系统,它将将数字转换为名称,这样当我想更改某个类的名称时,我只会在这个单独的数字到名称系统中执行,而不会更改数据

    这种方法的问题是:

  • 系统将变得脆弱。也就是说,改变数字命名系统中的任何东西都可能改变千兆字节数据的含义

  • 序列化数据将失去一些人类可读性,因为在序列化数据中,会有数字而不是名称

  • 我很抱歉把这么多的问题放在一个问题上,但我在编程方面缺乏经验,我所面临的问题似乎是如此巨大,以至于我不知道从哪里开始


    任何关于灵活序列化的通用材料、教程、习语或文献都是最受欢迎的

    也许可以帮你做这件事。

    现在可能有点晚了,但无论何时 如果是序列化格式,则应提供版本设置。 这可能会损坏流中的类型信息,或者 作为单独的(整数)字段处理。写课文的时候 你总是写最新的版本。读书的时候,你 必须先阅读类型和版本,然后才能 建构;如果您使用的是常见问题解答中建议的静态映射, 那么关键是:

    struct DeserializeKey
    {
        std::string type;
        int version;
    };
    
    考虑到你现在的处境,解决办法可能是 以清晰可识别的方式将版本更改为类型名称 顺便说一句,说点关于
    type_name___版本
    ;如果
    type_name
    后面没有两个下划线, 然后使用0。这不是最有效的方法,但它是 通常是可以接受的,并且可以解决向后的问题 兼容性,同时提供未来的进化

    关于你的确切问题:

  • 在本例中,
    派生的
    只是
    Derived1
    。您可以将必要的factory函数插入到 将地图放在相应的键下

  • 这只是经典版本。
    Base的版本0已发布
    一个
    field1
    属性,当反序列化时,使用它 初始化
    field1a
    ,然后将
    field1b
    初始化为空。
    Base
    的第2版同时具有这两种功能

  • 如果像我建议的那样,将版本更改为类型名称 在上面,您不必转换任何现有数据。长的 当然,也可以是一些旧版本 从数据集中消失,以便可以删除 支持他们,或者你的计划越来越大 支持很多旧版本。实际上,我通常
    可以看到后者。

    您不需要数字到名称或名称到数字的转换。您需要程序实体(类型、字段)到(外部的、可序列化的)名称映射。源代码中为这些实体指定的名称并不完全相关。您可以使用源名称作为默认外部名称,但应该有可能覆盖该名称。映射也不必是1:1,您可能希望将
    class NewWidget
    写入“NewWidget”,但将“Widget”和“NewWidget”读取为
    class NewWidget
    。此外,如果某个字段具有合理的默认值,则只需在序列化数据中找不到其值时使用它。这样你就可以不费吹灰之力地引入新的领域。这将自动满足您90%的需求。对于其他10%的需求,您将需要编写转换代码。永远不要从代码中删除旧的类和字段。为它们编写后反序列化例程,将它们转换为较新的对象。我非常喜欢将格式版本号添加到数据文件中(从第一个版本开始),以便读取它们的软件知道它在处理什么,并可能根据需要进行转换。@Loadmaster如果我理解正确,您保持旧数据“原样”,保留旧反序列化代码并将其应用于旧数据?谢谢,但您的链接对我来说太高级了。我不知道他们在说什么:(@MartinDrozdik,这对你来说似乎有点太晚了。(还有谷歌协议块。)通常情况下,序列化代码是生成的,而不是手工编写的,生成器会处理我在回答中提到的所有问题。但是,对于我来说,您找到一个生成器的可能性似乎很小,它会以某种奇迹般的危险生成您所使用的格式。谢谢!这是exac