Десериализация иерархии конструктора
(Этот вопрос очень похож наэтот, но на этот раз я звонюParent
десериализационный конструктор вChild
список инициализации).
В случае, когда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;
}
Таким образом, цепочка вызовов должна (и действительно) выглядеть следующим образом:
Выход:
Ребенок :: сериализации ()Родитель :: сериализации ()Входные данные:
Ребенок (архив)Родитель (архив)Родитель :: сериализации ()Тем не менееmParentData
заканчивается как0
вchildRead
когда я ожидал, что это будет1.2
.
Кто-нибудь может определить ошибку?
----------- РЕДАКТИРОВАТЬ -----------
Как указывает @stijn, в случае, когда у ребенка нет дополнительных данных для сериализации, мы можем просто удалитьserialize()
функция от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
}
};
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::serialize()
отChild
десериализационный конструктор? Или установите флаг, чтобы явно не десериализоватьParent
отChild::serialize()
если он вызывается изChild
десериализационный конструктор?
Если мы изменимChild::serialize()
к следующему, я получаю segfault:
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;
}