c++ - boost::serialization with immutable abstract base and virtual inheritance -


the code below current thinking permit boost::serialization of immutable abstract base virtual inheritance. hope missed , there simpler solution...?

as stands, raises few questions:

  1. is comment in iobject::serialize valid?
  2. the comment in bs::save_construct_data house seems indicate bug in boost::serialization. correct, or there better way this?
  3. is there more elegant way deserialise building deserialise function combined protected constructor?
  4. the result of (3) building implementation necessitate chunk of duplicated code. suspect require bit of crtp mitigate - alternatives?
  5. how 1 make work if virtual base contains data members? suspect similar (or identical) building::deserialise.
      #include <fstream>     #include <boost/archive/xml_oarchive.hpp>     #include <boost/archive/xml_iarchive.hpp>     #include <boost/serialization/export.hpp>      namespace bs = boost::serialization;      // ibase comes external library, , not interested in     // serialising ibase*.     class ibase {     public:       virtual ~ibase(){};     };      class iobject : public virtual ibase {     private:       friend class bs::access;       template <class archive>       void serialize(archive &ar, const unsigned int version) {         std::cout << "called iobject's serialize\n";         // ibase contains no members there no need serialise to/from         // archive. however, inheritance relationship must registered in         // boost::serialization. cannot use base_object this: try         // static_cast *this ibase, might not have created instance         // yet, in case there no virtual table , structured exception         // generated.         bs::void_cast_register<iobject, ibase>(static_cast<iobject *>(nullptr),                                                static_cast<ibase *>(nullptr));       }      public:       virtual ~iobject() {}     };      class ibuilding : public virtual ibase {     private:       friend class bs::access;       template <class archive>       void serialize(archive &ar, const unsigned int version) {         std::cout << "called ibuilding's serialize\n";         bs::void_cast_register<ibuilding, ibase>(static_cast<ibuilding *>(nullptr),                                                  static_cast<ibase *>(nullptr));       }      public:       virtual ~ibuilding() {}     };      /* tedious forward declarations permit later friending. */     class building;     class house;      namespace boost {     namespace serialization {     template <class archive>     inline void save_construct_data(archive &ar, const building *t,                                     const unsigned int version);     template <class archive>     inline void save_construct_data(archive &ar, const house *t,                                     const unsigned int version);     template <class archive>     inline void load_construct_data(archive &ar, house *t,                                     const unsigned int version);     }     }     /* tedious forward declarations end. */      class building : public ibuilding, public iobject {     private:       friend class bs::access;       template <class archive>       void serialize(archive &ar, const unsigned int version) {         std::cout << "called building's serialize\n";         // can use base_object here because although instance might not         // created, memory has been allocated. since there no virtual         // inheritance, static_cast can succeed.         ar &bs::make_nvp("iobject", bs::base_object<iobject>(*this));         ar &bs::make_nvp("ibuilding", bs::base_object<ibuilding>(*this));       }        template <class archive>       inline friend void bs::save_construct_data(archive &ar, const building *t,                                                  const unsigned int version);        const double weight_;      protected:       const double height_;        // members, associated constructor, , deserialise facilitate recreating       // immutable base.       struct members {         double weight_;         double height_;       };       building(const members &members)           : weight_(members.weight_), height_(members.height_) {}       template <class archive> const members deserialise(archive &ar) const {         double weight;         double height;         ar >> bs::make_nvp("weight_", weight) >> bs::make_nvp("height_", height);         return {weight, height};       }      public:       bool operator==(const building &other) const {         return weight_ == other.weight_ && height_ == other.height_;       }        virtual double height() const = 0;     };      class house : public building {     private:       template <class archive>       inline friend void bs::save_construct_data(archive &ar, const house *t,                                                  const unsigned int version);       template <class archive>       inline friend void bs::load_construct_data(archive &ar, house *t,                                                  const unsigned int version);        template <class archive>       explicit house(archive &ar) : building(deserialise(ar)) {}      public:       house(double weight, double height) : building({weight, height}) {}       virtual double height() const { return height_; }     };      boost_class_export(house);      namespace boost {     namespace serialization {     template <class archive>     inline void save_construct_data(archive &ar, const building *t,                                     const unsigned int version) {       std::cout << "called building's save_construct_data\n";       ar << make_nvp("weight_", t->weight_) << make_nvp("height_", t->height_);     }      template <class archive>     inline void bs::save_construct_data(archive &ar, const house *t,                                         const unsigned int version) {       std::cout << "called house's save_construct_data\n";       const auto &base = base_object<const building>(*t);       ar << make_nvp("building", base);       // ar << make_nvp("building", &base); doesn't seem work.       // serialising out reference calls building's serialize method,       // save_construct_data called pointer. means       // have call explicitly.       save_construct_data(ar, &base, version);     }      template <class archive>     inline void bs::load_construct_data(archive &ar, house *t,                                         const unsigned int version) {       std::cout << "called house's load_construct_data\n";       ar >> make_nvp("building", base_object<building>(*t));       ::new (t) house{ar};     }     }     }      int main() {       const char *file_name = "house.ser";       const bool save_first = true;        const house house(45367, 2.43);       std::cout << house.height() << "\n";       const iobject *ihouse = &house;        if (save_first) {         std::ofstream ofs(file_name);         boost::archive::xml_oarchive oa(ofs);         oa << boost_serialization_nvp(ihouse);       }        ibuilding *ihouse2;       {         std::ifstream ifs(file_name);         boost::archive::xml_iarchive ia(ifs);         ia >> boost_serialization_nvp(ihouse2);       }        if (dynamic_cast<const building &>(*ihouse) ==           dynamic_cast<const building &>(*ihouse2))         std::cout << "ok\n";       else         std::cout << "uh oh\n";        return 0;     }  

i don't believe comment correct. believe void_cast_register un-necessary since ibase known virtual base class of iobject.

futhermore, if don't add serialization_support free functions ibase, won't able serialise/deserialise ibase*, iobject* (although think that's fine unless managing ownership through ibase rather iobject).


Comments

Popular posts from this blog

sublimetext3 - what keyboard shortcut is to comment/uncomment for this script tag in sublime -

java - No use of nillable="0" in SOAP Webservice -

ubuntu - Laravel 5.2 quickstart guide gives Not Found Error -