(この質問は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;
}
だから、呼び出しチェーンがすべき(とい)は次のようになります。
出力:
- 子供::シリアル化()
- 親::シリアル化()
入力:
- 子供(アーカイブ)
- 親(アーカイブ)
- 親::シリアル化()
しかし、mParentData
は、私はそれが1.2
ことを期待するとき、childRead
で0
として終わります。
誰でもエラーを検出できますか?
-----------子供がシリアル化する追加のデータを持っていない場合には、@stijnで指摘したようにEDIT -----------
#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
からserialize()
機能を削除することができますそれは次のようなものである必要があるようですが、かなりではありません。 Child
の逆シリアル化コンストラクタでは、Parent
の逆シリアル化コンストラクタと、関数を呼び出すChild::serialize()
関数の両方を呼び出すため、Parent
は2回直列化を試みます。この不正な動作は、ここに示されている:それはどういうわけかのように思える
#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()
から明示的に非直列化しないようにフラグを設定しますか?
我々は次のように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;
}
多分私は何かが不足しているかもしれませんが、Childの 'serialize()'関数を削除すれば、期待どおりに動作しますか?あなたがコメントで言うように、シリアル化するものがないので、関数は必要ではありません。親クラスへの呼び出しを '&'で行うのではなく、 'serialize'つまり、あなたはParent :: serializeまたはboost :: serialization :: serialize(archive、boost :: serialization :: base_object(* this)、version)を呼び出す必要があります。とにかくParent :: serializeを呼び出すことになるでしょう –
stijn
あなたはちょうど@stijnの通りです。シリアル化するデータを持つ親が唯一の場合は、 'Child :: serialize()'を完全に削除しても問題ありません。私は子供がどこにシリアル化する追加のデータを持っているのかという質問に事例を追加しました。 'Child :: serialize()'から 'Parent :: serialize(archive、version)'を呼び出そうとしましたが、segfaultsです。 (そしてboost :: serialization :: serialize(archive、boost :: serialization :: base_object (* this)、version); ') –
この場合、私はLukasの答えが行く方法だと思います。そうでない場合はポインタ/登録タイプがあり、ドキュメントは – stijn