Cereal 中的序列化和继承

Serialization and inheritance in Cereal

我希望我的程序在 JSON 文件中保存和读取配置结构。

但是,我在生成正确的 JSON 文件时遇到了问题。可能是继承问题。

JSON 输出(不正确):

  {
        "config": {
            "confVector": [
                {
                    "common": "a"
                },
                {
                    "common": "b"
                }
            ]
        }
    }

预期(正确)JSON:

  {
        "config": {
            "confVector": [
                {
                    "common": "a",
                    "a" : 1
                },
                {
                    "common": "b",
                    "b" : "b"
                }
            ]
        }
    }

代码:

具有公共元素的基本结构

struct Base
{
    std::string common;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(CEREAL_NVP(common));
    }
};

两种具体结构

struct A : public Base
{
    int a;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(cereal::make_nvp("Base", cereal::base_class<Base>(this)));
        ar(cereal::make_nvp("a", a));
    }
};

struct B : public Base
{
    std::string b;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(cereal::make_nvp("Base", cereal::base_class<Base>(this)));
        ar(cereal::make_nvp("b", b));
    }
};

struct Config
{
    std::vector<Base> confVector;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(CEREAL_NVP(confVector));
    }
};
CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, A)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, B)

主要:测试保存到 json 文件

int main()
{
    std::string workPath = MAKE_STR(PLC_PROGRAM);

    Config config;

    A a;
    a.a      = 1;
    a.common = "a";

    B b;
    b.b      = "b";
    b.common = "b";

    config.confVector.push_back(a);
    config.confVector.push_back(b);

    std::ofstream outstream;
    outstream.open(workPath + "/test.json");

    {
        cereal::JSONOutputArchive ar(outstream);
        ar(cereal::make_nvp("config", config));
    }

    outstream.close();
}

正在对您的对象进行切片。

std::vector<Base> confVector;

这是 Base 类型对象的向量。
如果你推入派生自 Base 的对象,那么它只会复制对象的基础部分。

A a;
B b;
config.confVector.push_back(a);  // a is of Type A not Base
config.confVector.push_back(b);  // b is of type B not Base

所以这两个对象在放入向量时都会被切片。

您可以存储指向对象的指针:

std::vector<Base> confVector;
...
config.confVector.push_back(&a);
config.confVector.push_back(&b);

我解决了这个问题。

struct Base
{
    Base()          = default;
    virtual ~Base() = default;

    std::string common;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(CEREAL_NVP(common));
    }
};

struct A : public Base
{
    A() = default;

    A(int v)
    {
        a = v;
    }

    int a;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(cereal::make_nvp("Base", cereal::base_class<Base>(this)));
        ar(a);
    }
};

struct B : public Base
{
    B() = default;

    B(std::string text)
    {
        b = text;
    }

    std::string b;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(cereal::make_nvp("Base", cereal::base_class<Base>(this)));
        ar(b);
    }
};

struct Config
{
    std::vector<std::shared_ptr<Base>> vector;

    template <class Archive>
    void serialize(Archive &ar)
    {
        ar(vector);
    }
};

CEREAL_REGISTER_TYPE(A)

CEREAL_REGISTER_TYPE_WITH_NAME(B, "ClassB")

CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, A)
CEREAL_REGISTER_POLYMORPHIC_RELATION(Base, B)

int main()
{

    std::string workPath = "/home/user/"

    {
        std::ofstream os(workPath + "polymorphism_test.json");
        cereal::JSONOutputArchive oarchive(os);

        std::shared_ptr<Base> ptr1 = std::make_shared<A>(123);
        std::shared_ptr<Base> ptr2 = std::make_shared<B>("foobar");

        Config op;
        op.vector.push_back(ptr1);
        op.vector.push_back(ptr2);

        oarchive(op);
    }

    {
        std::ifstream is(workPath + "polymorphism_test.json");
        cereal::JSONInputArchive iarchive(is);
        Config ip;
        iarchive(ip);
    }

    return 0;
}

输出:

{
    "value0": {
        "value0": [
            {
                "polymorphic_id": 2147483649,
                "polymorphic_name": "A",
                "ptr_wrapper": {
                    "id": 2147483649,
                    "data": {
                        "Base": {
                            "common": ""
                        },
                        "value0": 123
                    }
                }
            },
            {
                "polymorphic_id": 2147483650,
                "polymorphic_name": "ClassB",
                "ptr_wrapper": {
                    "id": 2147483650,
                    "data": {
                        "Base": {
                            "common": ""
                        },
                        "value0": "foobar"
                    }
                }
            }
        ]
    }
}