/**
* The following is an example of how to use Boost Serialization.
* After googling around, I wasn't able to find many quality
* examples that did anything interesting. And those examples I
* did find were always either too complicated or incomplete.
* This example fully compiles, but make sure to link in
* boost_serialization.
*/
// You must include this header in order to perform serialization
// on shared pointers in boost.
#include <boost/serialization/shared_ptr.hpp>
#include <boost/shared_ptr.hpp>
// This class is required for use of the macro BOOST_CLASS_EXPORT_GUID
#include <boost/serialization/export.hpp>
// These includes are necessary to build an archive. The archive
// handles operator &, which provides a generic serialization
// operation; this can serialize in or out.
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <iostream>
// My favorite stream type: stringstream. It's so flexible and
// easy to use.
#include <sstream>
#include <string>
/**
* The character class, which is the class we are going to serialize.
*/
class Character
{
public:
Character() {}
virtual ~Character() {}
void setName(std::string const& n) { this->name = n; }
std::string const& getName() const { return this->name; }
void setAge(int a) { this->age = a; }
int getAge() const { return this->age; }
void dump()
{
std::cout << this->name << "(" << this->age << ")" << std::endl;
dump_();
}
/**
* This is a brilliant mechanism provided by boost. If the
* method is never used it is never generated. The Archive
* can provide either input or output serialization because
* we pass by reference. Also, the Archive as a template
* parameter allows us to serialize it in so many different
* ways (xml, text, binary, etc.). Like I said, simply
* brilliant design!
*/
template <typename Archive>
void serialize(Archive& ar, unsigned int const /* version */)
{
ar & this->name;
ar & this->age;
}
private:
std::string name;
int age;
private:
virtual void dump_() { }
};
/**
* This is a simple derived class that has a little more information
* to it. This illustrates how boost takes care of serialization of
* derived classes.
*/
class ComicCharacter : public Character
{
public:
ComicCharacter() : Character() { }
template <typename Archive>
void serialize(Archive& ar, unsigned int const version)
{
// This is the way that is outlined in the boost documentation
// for serializing the derived/base classes. Without this line,
// you will get: "unregistered void cast" errors.
boost::serialization::void_cast_register( static_cast<ComicCharacter*>(0)
, static_cast<Character*>(0));
Character::serialize(ar, version);
ar & this->strip;
}
void setStrip(std::string const& s) { this->strip = s; }
std::string const& getStrip() const { return this->strip; }
private:
std::string strip;
private:
void dump_() { std::cout << " from strip: " << this->strip << std::endl; }
};
BOOST_CLASS_EXPORT_GUID(Character, "Character")
BOOST_CLASS_EXPORT_GUID(ComicCharacter, "ComicCharacter")
/**
* Main entry point.
*/
int main(int, char**)
{
// Create a stream object to write our output archive to.
std::stringstream out;
// Create an archive. This passes an ostream object in as a place to
// output the results of the serialization.
boost::archive::text_oarchive oa(out);
// Create a shared pointer to a comic character AS a
// comic character.
boost::shared_ptr<ComicCharacter> comicCharacter(new ComicCharacter());
comicCharacter->setName("Charlie Brown");
comicCharacter->setAge(8); // [2]
comicCharacter->setStrip("Peanuts");
// When I write to the archive I want to make sure that the
// operation occurs on the BASE CLASS. This illustrates that the
// polymorphic data is also written to the stream.
boost::shared_ptr<Character> baseCharacter = comicCharacter;
// Finally now write the base object to the stream.
oa << baseCharacter;
std::string const contents = out.str();
std::cout << "ARCHIVE CONTENTS: " << contents << std::endl;
// Create a stream for input and populate it with the serialized
// contents.
std::stringstream in;
in << contents;
// Now we create a text input archive, again passing in an ostream
// object.
boost::archive::text_iarchive ia(in);
// Create an empty Character shared pointer. Note that character is
// the base class. We serialized a ComicCharacter into the archive-
// therefore we should get one out.
boost::shared_ptr<Character> mysteryCharacter;
// Here is the deserialization call.
ia >> mysteryCharacter;
// Finally to prove that we indeed received a Comic Character
// named Charlie Brown:
mysteryCharacter->dump();
}
#if 0
The following is the result of running this example:
ARCHIVE CONTENTS: 22 serialization::archive 10 0 1 2 14 ComicCharacter 1 0
0 13 Charlie Brown 8 7 Peanuts
Charlie Brown(8)
from strip: Peanuts
In conclusion, using the serialization capabilities in boost to serialize
polymorphic types is difficult. Hopefully this thorough example helps
folks muddling their way through.
#endif
No comments:
Post a Comment