【问题标题】:Serialization with Cereal for polymorphic class using virtual inheritance使用虚拟继承对多态类进行 Cereal 序列化
【发布时间】:2015-08-27 10:11:10
【问题描述】:

我正在尝试使用 Cereal 1.1.2 序列化和反序列化多态类(具有虚拟继承)。我收到“访问冲突 - 没有 RTTI 数据!”当我在反序列化后尝试将其向下转换为派生类时出现异常。当我使用普通继承而不是虚拟继承时,它工作正常。我已经在 Visual Studio 2013 社区版的项目设置中启用了 RTTI (/GR)。这是我的代码:

class Boogie
{
    friend class cereal::access;
    virtual void virtualFunction() {}
    int boogieInt = 3;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(boogieInt);
    }
};

class Booga : virtual public Boogie
{
    friend class cereal::access;
public:
    void virtualFunction() {}
    int boogaInt = 2;
    template<class Archive>
    void serialize(Archive & archive)
    {
        archive(cereal::virtual_base_class<Boogie>(this), boogaInt);
    }
};

CEREAL_REGISTER_TYPE(Booga);

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        {
            std::shared_ptr<Boogie> boogie = std::make_shared<Booga>();
            std::ofstream ofs("Booga.txt");
            cereal::BinaryOutputArchive archive(ofs);
            archive(boogie);
            ofs.close();
        }

        std::shared_ptr<Boogie> deBoogie;
        std::ifstream ifs("Booga.txt");
        cereal::BinaryInputArchive iarchive(ifs);
        iarchive(deBoogie);

        std::shared_ptr<Booga> outBooga = std::dynamic_pointer_cast<Booga>(deBoogie);

        std::cout << outBooga->boogaInt << std::endl;

        std::cin.get();
    }
    catch (std::exception e)
    {
        std::cout << "EXCEPTION" << std::endl;
        std::cout << e.what() << std::endl;
    }
    return 0;
}

【问题讨论】:

  • 对我来说,您的示例只是段错误,因为它无法将反序列化的智能指针转换为子类...
  • 快速评论 - 在对结果进行任何操作之前,您应该始终确保档案已被销毁。当它们超出范围时,它们将被销毁。有关详细信息,请参阅documentation

标签: c++ inheritance serialization cereal


【解决方案1】:

您的问题是您正在保存和加载不同的类型 - 您的加载代码应该反映您的保存代码。

还请注意,您不需要在此处使用虚拟继承,因为您仅从单个父类派生 - 请参阅here 了解更多信息)。此外,请参阅我对您帖子的评论,了解如何以 RAII 方式正确使用档案。

您的输出可以指定为:

std::shared_ptr<Boogie> data = std::make_shared<Booga>();
archive( data ); // data is actually a Booga but we hold it in a Boogie ptr

请注意,即使我分配了一个 Booga 指针,我还是分配给了一个 Boogie 对象 - 这基本上是多态性的全部意义,除非你需要这样做,否则不要使用多态性。

现在当我们进行加载时,我们加载到我们序列化的相同类型:

std::shared_ptr<Boogie> data;
archive( data ); // data is actually a Booga object because of polymorphism

只要确保您实际传递给存档的变量的类型是相同的,不管它们实际上是什么,因为多态性。

【讨论】:

  • 我已经尝试过您之前指出的操作(分配给 Boogie,但分配给 Booga),但是当我尝试将其投射到 Booga 时它仍然崩溃。我还尝试在 Boogie 中添加一个虚函数并在 Booga 中覆盖它,当我在反序列化后调用它时,程序崩溃了。我需要虚拟继承,因为我正在从 Java 移植一些代码,并且某些类具有菱形结构,如果没有虚拟继承,我不知道如何解决。如果我删除虚拟继承,一切正常。
  • 我还把存档封装到一个块中,这样存档就会被销毁。
猜你喜欢
  • 2018-12-19
  • 2016-03-09
  • 2013-11-19
  • 2018-05-14
  • 1970-01-01
  • 2011-10-15
  • 2014-11-23
  • 2017-03-31
  • 2015-11-21
相关资源
最近更新 更多