c++ - 反序列化构造函数层次结构

标签 c++ serialization boost boost-serialization

(这个问题和this one非常相似,但是这次我调用了Child初始化列表中的Parent反序列化构造函数)。

Child 没有添加要序列化的新数据的情况下, Parent 没有默认构造函数,我希望能够序列化 Parent 对象直接和 Child 对象一样,而且子对象和父对象都没有默认构造函数,看来我们应该使用下面的模式,子对象反序列化构造函数初始化父对象(也使用其反序列化构造函数)在初始化列表中:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    Child(const double data) : Parent(data) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        // Do nothing, as the only data to read is in Parent
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        // Let the parent do its serialization
        archive & boost::serialization::base_object<Parent>(*this);

        // Nothing else to do, as the only data to read/write is in Parent
    }
};

int main()
{
    Child child(1.2);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
    }

    return 0;
}

因此调用链应该(并且确实)如下所示:

输出:

  • child ::序列化()
  • 父级::序列化()

输入:

  • child (存档)
  • parent (存档)
  • 父级::序列化()

但是,mParentDatachildRead 中最终为 0,而我希望它是 1.2 .

谁能发现错误?

------------ 编辑------------

正如@stijn 所指出的,在 child 没有额外数据要序列化的情况下,我们可以简单地从 Child 中完全删除 serialize() 函数,像这样:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    Child(const double data) : Parent(data) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        // Do nothing, as the only data to read is in Parent
    }

};

int main()
{
    Child child(1.2);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
    }

    return 0;
}

但是,如果子项和父项都有要序列化的数据,并且它们都没有默认构造函数,则模式似乎需要像下面这样,但不完全是。在 Child 反序列化构造函数中,我们既调用了 Parent 反序列化构造函数,也调用了 Child::serialize() 函数,它调用了Parent::serialize() 函数,因此 Parent 会尝试反序列化两次。此处演示了这种不正确的行为:

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
    double mParentData;

    Parent(const double data) : mParentData(data) {}

    template<typename TArchive>
    Parent(TArchive& archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        archive & mParentData;
    }
};

class Child : public Parent
{
public:

    double mChildData;

    Child(const double parentData, const double childData) : Parent(parentData), mChildData(childData) {}

    template<typename TArchive>
    Child(TArchive& archive) : Parent(archive)
    {
        archive >> *this;
    }

    template<class TArchive>
    void serialize(TArchive& archive, const unsigned int version)
    {
        // Let the parent do its serialization
        archive & boost::serialization::base_object<Parent>(*this);

        // Do the child serialization
        archive & mChildData;
    }
};

int main()
{
    Child child(1.2, 3.4);

    {
        std::ofstream outputStream("test.txt");
        boost::archive::text_oarchive outputArchive(outputStream);

        outputArchive << child;
        outputStream.close();
    }

    {
        std::ifstream inputStream("test.txt");
        boost::archive::text_iarchive inputArchive(inputStream);
        Child childRead(inputArchive);

        std::cout << "childRead:" << std::endl
                  << childRead.mParentData << std::endl  // Outputs 0.2 (expected 1.2)
                  << childRead.mChildData << std::endl; // Outputs 3.4 correctly
    }

    return 0;
}

似乎我们需要从 Child 反序列化构造函数中调用不同版本的 Child::serialize() ?或者设置一个标志,如果它是从 Child 反序列化构造函数调用的,则不从 Child::serialize() 显式反序列化 Parent

如果我们将 Child::serialize() 更改为以下内容,我会得到一个段错误:

template<class TArchive>
void serialize(TArchive& archive, const unsigned int version)
{
    // Let the parent do its serialization
    Parent::serialize(archive, version);

    // Do the child serialization
    archive & mChildData;
}

最佳答案

我相信您不需要将反序列化转发给父级。 将您的代码更改为

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <fstream>

class Parent
{
public:
  double mParentData;

  Parent(const double data) : mParentData(data) {}

  template<typename TArchive>
  Parent(TArchive& archive, bool deserialize = false)
  {
    if (!deserialize)
      archive >> *this;
  }

  template<class TArchive>
  void serialize(TArchive& archive, const unsigned int version)
  {
    archive & mParentData;
  }
};

class Child : public Parent
{
public:

  Child(const double data) : Parent(data) {}

  template<typename TArchive>
  Child(TArchive& archive) : Parent(archive, true)
  {
    archive >> *this;
  }

  template<class TArchive>
  void serialize(TArchive& archive, const unsigned int version)
  {
    // Let the parent do its serialization
    archive & boost::serialization::base_object<Parent>(*this);

    // Nothing else to do, as the only data to read/write is in Parent
  }
};

int main()
{
  {
    Child child(1.2);
    std::ofstream outputStream("test.txt");
    boost::archive::text_oarchive outputArchive(outputStream);

    outputArchive << child;
    outputStream.close();
  }

  {
    std::ifstream inputStream("test.txt");
    boost::archive::text_iarchive inputArchive(inputStream);
    Child childRead(inputArchive);


    std::cout << "childRead:" << std::endl
      << childRead.mParentData << std::endl; // Outputs 0 (expected 1.2)
  }

  return 0;
}

对我有用。

关于c++ - 反序列化构造函数层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36222439/

相关文章:

c++ - 当人们谈论并发时, "transaction"是什么意思?

ruby - 为什么 DataMapper 对象和集合上的 `to_json` 会导致无限查询?

json - 如何对使用转换器的 Grails 服务进行单元测试?

java - 简单的 Jackson XML 反序列化到 Java 不起作用

c++ - 用 std/tr1/boost::array 替换内置数组总是安全的吗?

c++ - Boost 编译标志 gcc 错误

c++ - 比较 -INT_MIN (GCC)

c++ - 避免对实现接口(interface)的类进行多个几乎相同的声明

c++ - LevelDB:IO 错误:XXX.sst:打开的文件太多

c++ - 如何使用 Boost 解压缩压缩数据的 vector ?