Hi, I am trying to understand the differences between intrusive and non-intrusive style of serialization for derived classes. The classes I want to serialize look like: class Base {} template<class TYPE> class Derived : public Base , public std::vector<TYPE> {} where it is intended that TYPE is a built in C type (int, double, ...) I'm starting by trying to understand the demo.cpp example since that example serializes derived classes. My first goal is to serialize bus_stop_corner and bus_stop_destination directly through the base class. These are serialized through a pointer indirectly when bus_stop_schedule is serialized; however, I've been unable to do this directly. I've gone about it using the pseudo-code in 'Pointers to Objects of Derived Classes'; however, I get the following compilation error: g++ -g demo2.cpp -o demo2 /usr/lib/libboost_serialization.a (I'm using g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)) /usr/include/boost/archive/detail/oserializer.hpp: In function $-1òøvoid boost::archive::save(Archive&, T&) [with Archive = boost::archive::text_oarchive, T = bus_stop*]òù: /usr/include/boost/archive/basic_text_oarchive.hpp:78: instantiated from $-1òøvoid boost::archive::basic_text_oarchive<Archive>::save_override(T&, int) [with T = bus_stop*, Archive = boost::archive::text_oarchive]òù /usr/include/boost/archive/detail/interface_oarchive.hpp:78: instantiated from $-1òøArchive& boost::archive::detail::interface_oarchive<Archive>::operator<<(T&) [with T = bus_stop*, Archive = boost::archive::text_oarchive]òù demo2.cpp:164: instantiated from here /usr/include/boost/archive/detail/oserializer.hpp:567: error: invalid application of $-1òøsizeofòù to incomplete type òøboost::STATIC_ASSERTION_FAILURE<false>òù I've also tried by taking the full demo.cpp, and creating a function, save_stop, modeled after save_schedule. This compiles but saves only the base class. This larger piece of code is below, after ++++++++++++++++++. Differences from demo.cpp are marked with //<<<< Obviously, I'm missing something; hopefully, something simple. Any help greatly appreciated. Thanks. --Len /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 // demo.cpp // // (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include <iomanip> #include <iostream> #include <fstream> #include <string> #include <boost/archive/tmpdir.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/base_object.hpp> #include <boost/serialization/utility.hpp> #include <boost/serialization/list.hpp> class gps_position { friend std::ostream & operator<<(std::ostream &os, const gps_position &gp); friend class boost::serialization::access; int degrees; int minutes; float seconds; template<class Archive> void serialize(Archive & ar, const unsigned int /* file_version */){ ar & degrees & minutes & seconds; } public: // every serializable class needs a constructor gps_position(){}; gps_position(int _d, int _m, float _s) : degrees(_d), minutes(_m), seconds(_s) {} }; std::ostream & operator<<(std::ostream &os, const gps_position &gp) { return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"'; } ///////////////////////////////////////////////////////////// // One bus stop // // illustrates serialization of serializable members // class bus_stop_corner; class bus_stop_destination; class bus_stop { friend class boost::serialization::access; friend std::ostream & operator<<(std::ostream &os, const bus_stop &gp); virtual std::string description() const = 0; gps_position latitude; gps_position longitude; template<class Archive> void serialize(Archive &ar, const unsigned int version) { // register all derived classes. ar.register_type(static_cast<bus_stop_corner>(NULL)); ar.register_type(static_cast<bus_stop_destination>(NULL)); ar & latitude; ar & longitude; } protected: bus_stop(const gps_position & _lat, const gps_position & _long) : latitude(_lat), longitude(_long) {} public: bus_stop(){} // virtual void serialize(std::ostream &ar, const unsigned int file_version) = 0; virtual ~bus_stop(){} }; BOOST_IS_ABSTRACT(bus_stop) std::ostream & operator<<(std::ostream &os, const bus_stop &bs) { return os << bs.latitude << bs.longitude << ' ' << bs.description(); } ///////////////////////////////////////////////////////////// // Several kinds of bus stops // // illustrates serialization of derived types // class bus_stop_corner : public bus_stop { friend class boost::serialization::access; std::string street1; std::string street2; virtual std::string description() const { return street1 + " and " + street2; } template<class Archive> void serialize(Archive &ar, const unsigned int version) { // save/load base class information ar & boost::serialization::base_object<bus_stop>(*this); ar & street1 & street2; } public: bus_stop_corner(){} // virtual void serialize(std::ostream &ar, const unsigned int file_version){ // ar << "bus_stop_corner"; // }; bus_stop_corner(const gps_position & _lat, const gps_position & _long, const std::string & _s1, const std::string & _s2 ) : bus_stop(_lat, _long), street1(_s1), street2(_s2) { } }; class bus_stop_destination : public bus_stop { friend class boost::serialization::access; std::string name; virtual std::string description() const { return name; } template<class Archive> void serialize(Archive &ar, const unsigned int version) { description(); ar & boost::serialization::base_object<bus_stop>(*this) & name; } public: bus_stop_destination(){} // virtual void serialize(std::ostream &ar, const unsigned int file_version){ // ar << "bus_stop_destination"; // }; bus_stop_destination( const gps_position & _lat, const gps_position & _long, const std::string & _name ) : bus_stop(_lat, _long), name(_name) { } }; int main(int argc, char *argv[]) { // fill in the data // make a few stops bus_stop_corner *bsc0; bus_stop *bs0 = bsc0 = new bus_stop_corner( gps_position(34, 135, 52.560f), gps_position(134, 22, 78.30f), "24th Street", "10th Avenue" ); std::ofstream ofs("demofile1.txt"); boost::archive::text_oarchive oa(ofs); oa << bs0; } ++++++++++++++++++++++++++++++++++++++ /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 // demo.cpp // // (C) Copyright 2002-4 Robert Ramey - http://www.rrsd.com . // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include <iomanip> #include <iostream> #include <fstream> #include <string> #include <boost/archive/tmpdir.hpp> #include <boost/archive/text_iarchive.hpp> #include <boost/archive/text_oarchive.hpp> #include <boost/serialization/base_object.hpp> #include <boost/serialization/utility.hpp> #include <boost/serialization/list.hpp> ///////////////////////////////////////////////////////////// // The intent of this program is to serve as a tutorial for // users of the serialization package. An attempt has been made // to illustrate most of the facilities of the package. // // The intent is to create an example suffciently complete to // illustrate the usage and utility of the package while // including a minimum of other code. // // This illustration models the bus system of a small city. // This includes, multiple bus stops, bus routes and schedules. // There are different kinds of stops. Bus stops in general will // will appear on multiple routes. A schedule will include // muliple trips on the same route. ///////////////////////////////////////////////////////////// // gps coordinate // // llustrates serialization for a simple type // class gps_position { friend std::ostream & operator<<(std::ostream &os, const gps_position &gp); friend class boost::serialization::access; int degrees; int minutes; float seconds; template<class Archive> void serialize(Archive & ar, const unsigned int /* file_version */){ ar & degrees & minutes & seconds; } public: // every serializable class needs a constructor gps_position(){}; gps_position(int _d, int _m, float _s) : degrees(_d), minutes(_m), seconds(_s) {} }; std::ostream & operator<<(std::ostream &os, const gps_position &gp) { return os << ' ' << gp.degrees << (unsigned char)186 << gp.minutes << '\'' << gp.seconds << '"'; } ///////////////////////////////////////////////////////////// // One bus stop // // illustrates serialization of serializable members // class bus_stop { friend class boost::serialization::access; friend std::ostream & operator<<(std::ostream &os, const bus_stop &gp); virtual std::string description() const = 0; gps_position latitude; gps_position longitude; template<class Archive> void serialize(Archive &ar, const unsigned int version) { ar & latitude; ar & longitude; } protected: bus_stop(const gps_position & _lat, const gps_position & _long) : latitude(_lat), longitude(_long) {} public: bus_stop(){} virtual ~bus_stop(){} }; BOOST_IS_ABSTRACT(bus_stop) std::ostream & operator<<(std::ostream &os, const bus_stop &bs) { return os << bs.latitude << bs.longitude << ' ' << bs.description(); } ///////////////////////////////////////////////////////////// // Several kinds of bus stops // // illustrates serialization of derived types // class bus_stop_corner : public bus_stop { friend class boost::serialization::access; std::string street1; std::string street2; virtual std::string description() const { return street1 + " and " + street2; } template<class Archive> void serialize(Archive &ar, const unsigned int version) { // save/load base class information ar & boost::serialization::base_object<bus_stop>(*this); ar & street1 & street2; } public: bus_stop_corner(){} bus_stop_corner(const gps_position & _lat, const gps_position & _long, const std::string & _s1, const std::string & _s2 ) : bus_stop(_lat, _long), street1(_s1), street2(_s2) { } }; class bus_stop_destination : public bus_stop { friend class boost::serialization::access; std::string name; virtual std::string description() const { return name; } template<class Archive> void serialize(Archive &ar, const unsigned int version) { description(); ar & boost::serialization::base_object<bus_stop>(*this) & name; } public: bus_stop_destination(){} bus_stop_destination( const gps_position & _lat, const gps_position & _long, const std::string & _name ) : bus_stop(_lat, _long), name(_name) { } }; ///////////////////////////////////////////////////////////// // a bus route is a collection of bus stops // // illustrates serialization of STL collection templates. // // illustrates serialzation of polymorphic pointer (bus stop *); // // illustrates storage and recovery of shared pointers is correct // and efficient. That is objects pointed to by more than one // pointer are stored only once. In such cases only one such // object is restored and pointers are restored to point to it // class bus_route { friend class boost::serialization::access; friend std::ostream & operator<<(std::ostream &os, const bus_route &br); typedef bus_stop * bus_stop_pointer; std::list<bus_stop_pointer> stops; template<class Archive> void serialize(Archive &ar, const unsigned int version) { // in this program, these classes are never serialized directly but rather // through a pointer to the base class bus_stop. So we need a way to be // sure that the archive contains information about these derived classes. //ar.template register_type<bus_stop_corner>(); ar.register_type(static_cast<bus_stop_corner *>(NULL)); //ar.template register_type<bus_stop_destination>(); ar.register_type(static_cast<bus_stop_destination *>(NULL)); // serialization of stl collections is already defined // in the header ar & stops; } public: bus_route(){} void append(bus_stop *_bs) { stops.insert(stops.end(), _bs); } }; std::ostream & operator<<(std::ostream &os, const bus_route &br) { std::list<bus_stop *>::const_iterator it; // note: we're displaying the pointer to permit verification // that duplicated pointers are properly restored. for(it = br.stops.begin(); it != br.stops.end(); it++){ os << '\n' << std::hex << "0x" << *it << std::dec << ' ' << **it; } return os; } ///////////////////////////////////////////////////////////// // a bus schedule is a collection of routes each with a starting time // // Illustrates serialization of STL objects(pair) in a non-intrusive way. // See definition of operator<< <pair<F, S> >(ar, pair) and others in // serialization.hpp // // illustrates nesting of serializable classes // // illustrates use of version number to automatically grandfather older // versions of the same class. class bus_schedule { public: // note: this structure was made public. because the friend declarations // didn't seem to work as expected. struct trip_info { template<class Archive> void serialize(Archive &ar, const unsigned int file_version) { // in versions 2 or later if(file_version >= 2) // read the drivers name ar & driver; // all versions have the follwing info ar & hour & minute; } // starting time int hour; int minute; // only after system shipped was the driver's name added to the class std::string driver; trip_info(){} trip_info(int _h, int _m, const std::string &_d) : hour(_h), minute(_m), driver(_d) {} }; private: friend class boost::serialization::access; friend std::ostream & operator<<(std::ostream &os, const bus_schedule &bs); friend std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti); std::list<std::pair<trip_info, bus_route *> > schedule; template<class Archive> void serialize(Archive &ar, const unsigned int version) { ar & schedule; } public: void append(const std::string &_d, int _h, int _m, bus_route *_br) { schedule.insert(schedule.end(), std::make_pair(trip_info(_h, _m, _d), _br)); } bus_schedule(){} }; BOOST_CLASS_VERSION(bus_schedule, 2) std::ostream & operator<<(std::ostream &os, const bus_schedule::trip_info &ti) { return os << '\n' << ti.hour << ':' << ti.minute << ' ' << ti.driver << ' '; } std::ostream & operator<<(std::ostream &os, const bus_schedule &bs) { std::list<std::pair<bus_schedule::trip_info, bus_route *> >::const_iterator it; for(it = bs.schedule.begin(); it != bs.schedule.end(); it++){ os << it->first << *(it->second); } return os; } void save_schedule(const bus_schedule &s, const char * filename){ // make an archive std::ofstream ofs(filename); boost::archive::text_oarchive oa(ofs); oa << s; } //<<<< void save_stop(const bus_stop &s, const char * filename){ // make an archive std::ofstream ofs(filename); boost::archive::text_oarchive oa(ofs); oa.register_type(static_cast<bus_stop_corner* >(NULL)); //ar.template register_type<bus_stop_destination>(); oa.register_type(static_cast<bus_stop_destination* >(NULL)); oa << s; } //>>>> void restore_schedule(bus_schedule &s, const char * filename) { // open the archive std::ifstream ifs(filename); boost::archive::text_iarchive ia(ifs); // restore the schedule from the archive ia >> s; } int main(int argc, char *argv[]) { // make the schedule bus_schedule original_schedule; // fill in the data // make a few stops bus_stop *bs0 = new bus_stop_corner( gps_position(34, 135, 52.560f), gps_position(134, 22, 78.30f), "24th Street", "10th Avenue" ); //<<<< std::string filename1(boost::archive::tmpdir()); filename1 += "/demofile1.txt"; save_stop( *bs0 , filename1.c_str()); //>>>> bus_stop *bs1 = new bus_stop_corner( gps_position(35, 137, 23.456f), gps_position(133, 35, 54.12f), "State street", "Cathedral Vista Lane" ); bus_stop *bs2 = new bus_stop_destination( gps_position(35, 136, 15.456f), gps_position(133, 32, 15.300f), "White House" ); bus_stop *bs3 = new bus_stop_destination( gps_position(35, 134, 48.789f), gps_position(133, 32, 16.230f), "Lincoln Memorial" ); // make a routes bus_route route0; route0.append(bs0); route0.append(bs1); route0.append(bs2); // add trips to schedule original_schedule.append("bob", 6, 24, &route0); original_schedule.append("bob", 9, 57, &route0); original_schedule.append("alice", 11, 02, &route0); // make aother routes bus_route route1; route1.append(bs3); route1.append(bs2); route1.append(bs1); // add trips to schedule original_schedule.append("ted", 7, 17, &route1); original_schedule.append("ted", 9, 38, &route1); original_schedule.append("alice", 11, 47, &route1); // display the complete schedule std::cout << "original schedule"; std::cout << original_schedule; std::string filename(boost::archive::tmpdir()); filename += "/demofile.txt"; // save the schedule save_schedule(original_schedule, filename.c_str()); // ... some time later // make a new schedule bus_schedule new_schedule; restore_schedule(new_schedule, filename.c_str()); // and display std::cout << "\nrestored schedule"; std::cout << new_schedule; // should be the same as the old one. (except for the pointer values) delete bs0; delete bs1; delete bs2; delete bs3; return 0; }