2016-03-25 18 views
1

(この質問は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ことを期待するとき、childRead0として終わります。

誰でもエラーを検出できますか?

-----------子供がシリアル化する追加のデータを持っていない場合には、@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; 
} 
+0

多分私は何かが不足しているかもしれませんが、Childの 'serialize()'関数を削除すれば、期待どおりに動作しますか?あなたがコメントで言うように、シリアル化するものがないので、関数は必要ではありません。親クラスへの呼び出しを '&'で行うのではなく、 'serialize'つまり、あなたはParent :: serializeまたはboost :: serialization :: serialize(archive、boost :: serialization :: base_object (* this)、version)を呼び出す必要があります。とにかくParent :: serializeを呼び出すことになるでしょう – stijn

+0

あなたはちょうど@stijnの通りです。シリアル化するデータを持つ親が唯一の場合は、 'Child :: serialize()'を完全に削除しても問題ありません。私は子供がどこにシリアル化する追加のデータを持っているのかという質問に事例を追加しました。 'Child :: serialize()'から 'Parent :: serialize(archive、version)'を呼び出そうとしましたが、segfaultsです。 (そしてboost :: serialization :: serialize(archive、boost :: serialization :: base_object (* this)、version); ') –

+0

この場合、私はLukasの答えが行く方法だと思います。そうでない場合はポインタ/登録タイプがあり、ドキュメントは – stijn

答えて

0

私はあなたが親に、デシリアライゼーションを転送する必要がないと考えています。 コードを

に変更する
#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; 
} 

私のために働きます。

+0

を確認しているようです。私はデフォルトコンストラクタを必要としないと明示的に言及していません。これは、すべてのものと 'archive>オブジェクトとの間でデシリアライズするコンストラクタを使用する理由のすべてです。 ' –

+0

参照してください。私のアプローチを使用して、 'Parent'クラスの空の直列化復元コンストラクタと、' Child'クラスの逆直列化ロジックを保持します。テンプレート 子(TArchive&アーカイブ):親(アーカイブ) { archive >> * this; } '。この方法を使用すると、デフォルトのctorを削除することができます。編集された記事を参照してください。 – foo

+0

それは 'Child'のためにはうまくいくでしょうが、' Parent'を直接直列化して逆シリアル化することはできません。 (例えば、 '親の親(1.2); outArchive <<親;親のreadParent(inArchive);) –

関連する問題