Boost::Serialization is your answer. You should read up on it more, since it does precisely what you're asking, and handles pointers quite well, even polymorphic pointers.
Here's a quick example I whipped up. A lot of the bloat comes from just filler access code and polymorphic serialization.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
#include <boost/filesystem.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/export.hpp>
#include <fstream>
#include <iostream>
struct Person;
void savePerson(Person& person);
void loadPerson(Person& person);
class Race {
public:
Race() {}
Race(std::string name) : raceName(name) { }
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar, const unsigned version)
{
ar & raceName;
}
std::string raceName;
};
class Human : public Race {
public:
Human() : Race("Human") {}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar, const unsigned version)
{
ar & boost::serialization::base_object<Race>(*this);
}
};
class Alien : public Race {
public:
Alien() : Race("Alien") {}
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar, const unsigned version)
{
ar & boost::serialization::base_object<Race>(*this);
}
};
class Person
{
public:
std::string name;
Race* race;
friend class boost::serialization::access;
template<typename Archive>
void serialize(Archive& ar, const unsigned version)
{
ar & name;
ar & race;
}
};
BOOST_CLASS_EXPORT_GUID(Human, "Human");
BOOST_CLASS_EXPORT_GUID(Alien, "Alien");
int main()
{
Person myPerson;
myPerson.name = "Test";
myPerson.race = new Alien();
savePerson(myPerson);
Person newPerson;
loadPerson(newPerson);
std::cout << newPerson.race->raceName;
}
void savePerson(Person& person)
{
std::ofstream outputStream;
outputStream.open("myPerson.txt");
boost::archive::text_oarchive outputArchive(outputStream);
outputArchive << person;
outputStream.close();
}
void loadPerson(Person& person)
{
std::ifstream inputStream;
if(boost::filesystem::exists("myPerson.txt"))
{
inputStream.open("myPerson.txt", std::ifstream::in);
boost::archive::text_iarchive inputArchive(inputStream);
inputArchive >> person;
}
if(inputStream.is_open())
inputStream.close();
}
|
In this example I save and load a Person from and to and new object. The corresponding serialization file is:
1 2
|
22 serialization::archive 17 0 0 4 Test 1 1 0
0 5 Alien
|
As you can see it captures the polymorphic type "Alien" fine, even when it's a pointer. But you'll also notice I had to register the polymorphic types with the archive beforehand, so the library knew what to do with them.
Also note that unless you want to do some "load_construct data" magic, it's easier to just create each of your classes with a default constructor for boost::serialization to utilize. Otherwise, if the class has no default constructor you basically have to "teach" boost serialization how to construct your object, which adds even more bloat.
Let me know if you have any questions.