Boost Serialize and derived classes
I can't seem to figure out if what I want is possible. I am using the Boost Serialization library to save the state of my program. I have a manager-type class which holds onto pointers of a base class. The Boost Serialization website has a lot to say about base and derived classes. In a tutorial they show one way to deal with them. But it assumes a priori knowledge of the derived classes: 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)); // TYPES KNOWN A PRIORI //ar.template register_type<bus_stop_destination>(); ar.register_type(static_cast<bus_stop_destination *>(NULL)); // TYPES KNOWN A PRIORI // serialization of stl collections is already defined // in the header ar & BOOST_SERIALIZATION_NVP(stops); } public: bus_route(){} void append(bus_stop *_bs) { stops.insert(stops.end(), _bs); } }; In my code, however, I don't know exactly what the derived classes might be. The derived objects are created and passed back to my manager class through the base pointer. One option I was considering was that when plugins register with the program, they would have to also register the derived class names with the archive. How this would actually be implemented, I have no idea. Can an archive object be created independently from the Serialization library, modified and then sent back to Serialization? Here is a simple test case I am working on, but I just can't get it to write out the derived classes to file: class base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(val); } public: base() : val(0.0) {} base(double b) : val(b) {} double val; }; class derived : public base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::void_cast_register<derived, base>(static_cast<derived *>(NULL),static_cast<base *>(NULL)); ar & BOOST_SERIALIZATION_NVP(val); } public: derived() : base(0.0), val(0) {} derived(int a, double b) : base(b), val(a) {} int val; }; BOOST_CLASS_EXPORT_GUID(derived, "derived"); class manager { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(objs); } public: std::list<base*> objs; }; void main() { manager mgr; // Creat some data to save derived *d1, *d2, *d3, *d4; d1 = new derived(1, 1.0); d2 = new derived(2, 3.0); mgr.objs.push_back( d1 ); mgr.objs.push_back( d2 ); { std::ofstream ofs("out.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(mgr); ofs.close(); } manager new_mgr; { std::ifstream ifs("out.xml"); assert(ifs.good()); boost::archive::xml_iarchive ia(ifs); ia >> BOOST_SERIALIZATION_NVP(new_mgr); ifs.close(); } { std::ofstream ofs("check.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(new_mgr); ofs.close(); } delete d1, d2; } I apologize if this commonly asked but I was just looking for some insight as to the best approach. J.D.
Yea I have done that. I have read the sections on exporting several times and thought my example was implementing this feature correctly. Yet every time I run it, the code only spits out the base class. The only complete example from the documentation shows the explicit declaration of derived class names. Once again, here is my test code: main.cpp: class base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(dval); } public: base() : dval(0.0) {} base(double b) : dval(b) {} double dval; }; class derived : public base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::void_cast_register<derived, base>(static_cast<derived *>(NULL),static_cast<base *>(NULL)); ar & BOOST_SERIALIZATION_NVP(ival); } public: derived() : base(0.0), ival(0) {} derived(int a, double b) : base(b), ival(a) {} int ival; }; BOOST_CLASS_EXPORT_GUID(derived, "derived"); class manager { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(objs); } public: std::list<base*> objs; }; void SerializeTest::testSerialize() { manager mgr; // Creat some data to save derived *d1, *d2; d1 = new derived(1, 1.0); d2 = new derived(2, 3.0); mgr.objs.push_back( d1 ); mgr.objs.push_back( d2 ); { std::ofstream ofs("out.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(mgr); ofs.close(); } manager new_mgr; { std::ifstream ifs("out.xml"); assert(ifs.good()); boost::archive::xml_iarchive ia(ifs); ia >> BOOST_SERIALIZATION_NVP(new_mgr); ifs.close(); } { std::ofstream ofs("check.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(new_mgr); ofs.close(); } delete d1, d2; } And here is the output of out.xml: <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization> <boost_serialization signature="serialization::archive" version="4"> <mgr class_id="0" tracking_level="0" version="0"> <objs class_id="1" tracking_level="0" version="0"> <count>2</count> <item_version>0</item_version> <item class_id="2" tracking_level="1" version="0" object_id="_0"> <dval>1</dval> </item> <item class_id_reference="2" object_id="_1"> <dval>3</dval> </item> </objs> </mgr> On Tue, Sep 16, 2008 at 6:32 PM, Robert Ramey <ramey@rrsd.com> wrote:
Look in the documentation of "export" and BOOST_CLASS_EXPORT
-- J.D. Yamokoski Department of Mechanical & Aerospace Engineering University of Florida MAE-A Room 331 Gainesville, FL 32611 e-mail: yamokosk@gmail.com fax: (352) 392-7303
the base class MUST be polymorphic - that it it must have at least one virtual function. A practical suggestion would be to make at least one of those functions abstract ( a() = 0) so that you can't accidently "slice" off the derived class. Robert Ramey John Yamokoski wrote:
Yea I have done that. I have read the sections on exporting several times and thought my example was implementing this feature correctly. Yet every time I run it, the code only spits out the base class. The only complete example from the documentation shows the explicit declaration of derived class names. Once again, here is my test code:
main.cpp:
class base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(dval); } public: base() : dval(0.0) {} base(double b) : dval(b) {} double dval; };
class derived : public base { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { boost::serialization::void_cast_register<derived, base>(static_cast<derived *>(NULL),static_cast<base *>(NULL)); ar & BOOST_SERIALIZATION_NVP(ival); } public: derived() : base(0.0), ival(0) {} derived(int a, double b) : base(b), ival(a) {} int ival; };
BOOST_CLASS_EXPORT_GUID(derived, "derived");
class manager { friend class boost::serialization::access; template<class Archive> void serialize(Archive & ar, const unsigned int file_version) { ar & BOOST_SERIALIZATION_NVP(objs); } public: std::list<base*> objs; };
void SerializeTest::testSerialize() { manager mgr;
// Creat some data to save derived *d1, *d2; d1 = new derived(1, 1.0); d2 = new derived(2, 3.0);
mgr.objs.push_back( d1 ); mgr.objs.push_back( d2 );
{ std::ofstream ofs("out.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(mgr); ofs.close(); }
manager new_mgr;
{ std::ifstream ifs("out.xml"); assert(ifs.good()); boost::archive::xml_iarchive ia(ifs); ia >> BOOST_SERIALIZATION_NVP(new_mgr); ifs.close(); }
{ std::ofstream ofs("check.xml"); assert(ofs.good()); boost::archive::xml_oarchive oa(ofs); oa << BOOST_SERIALIZATION_NVP(new_mgr); ofs.close(); }
delete d1, d2; }
And here is the output of out.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <!DOCTYPE boost_serialization> <boost_serialization signature="serialization::archive" version="4"> <mgr class_id="0" tracking_level="0" version="0"> <objs class_id="1" tracking_level="0" version="0"> <count>2</count> <item_version>0</item_version> <item class_id="2" tracking_level="1" version="0" object_id="_0"> <dval>1</dval> </item> <item class_id_reference="2" object_id="_1"> <dval>3</dval> </item> </objs> </mgr>
On Tue, Sep 16, 2008 at 6:32 PM, Robert Ramey <ramey@rrsd.com> wrote:
Look in the documentation of "export" and BOOST_CLASS_EXPORT
participants (2)
-
John Yamokoski
-
Robert Ramey