Reputation: 43
I'm trying to (de)serialize a polymorphic vector, but have different issues with different attempts. The entire order of events are:
I have Class Derived (and DerivedB, DerivedC etc) which derives from Class Base & a Class LotsOfBases which holds a Vector of Virtual Base.
Although, I don't see how this could be causing the issue - I believe my issue is because the objects in the Vector coming from the Server are in a particular order (AAABBCCCCD) and when they come back they are in a random order and may have different quantities of derived classes (ABABCDDDA).
Below are my failed attempts. Using method 2 below, if I am lucky I can send information back and forth (if class order remains the same), but when the class types change order, the problems begin to occur.
Code Used & Compile/Runtime Error:
Compiles with no additions of course, but I get RunTime issues as Boost doesn't know which class is which... So I tried:
ar.template register_type<Derived>() ;
- Registering Class in "LotsOfBases.h"'s Serialize Function and got the following when called at RunTime: Error @ RunTime: what(): Input Stream Error
- This is where I've had most success and what is mainly mentioned above.
ar.register_type<static...
But I get compile errors stating its a function (saw this else where on StackOverflow
BOOST_CLASS_EXPORT(Derived) ;
At the end of the ".h" file which gives n warnings for each different sub-class of Base and fails to compile. Error: multiple definition of ``boost::archive::detail::extra_detail::init_guid<Derived>::g'
I tried to register the classes with the archiver in the main where LotsOfBases gets Deserialised. Compiler warnings
BOOST_CLASS_EXPORT_IMPLEMENT(TextQuestion)
from Exporting Class Serialization - Same errors as 6 iirc.
The examples above without links are from my trolling through ~30 pages on StackOverflow which are similar but their solutions offered don't seem to work for me or are to do with Boost Serialization but somewhat irrelevant.
The following is a shortened version of my code (without edits used from elsewhere):
Classes' Code
LotsOfBases:
#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }
class LotsOfBases
{
public:
std::vector<Base *> getAllBases() ;
protected:
std::vector<Base *> allBases() ;
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & allBases ;
}
} ;
Base:
#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }
class Base
{
public:
Base() ;
~Base() ;
virtual std::string getBaseLocation() ;
protected:
std::string baseLocation ;
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & baseLocation ;
}
} ;
Derived
#include "s11n.h" //Import All Serialization Headers In Correct Order
namespace boost { namespace serialization { class access ; } }
class Derived
{
public:
Derived() ;
bool getIsAttackableBase() ;
private:
bool isAttackableBase ;
typedef Base _super;
friend class boost::serialization::access ;
template <typename Archive>
void serialize(Archive& ar, const unsigned int /*version*/)
{
ar & boost::serialization::base_object<_super>(*this) ;
ar & isAttackableBase ;
}
I'm sure it shouldn't be so difficult. So, I guess my question is... What am I doing wrong? Where should I start reading/researching now?
Upvotes: 3
Views: 2656
Reputation: 214
I, as you, had searched for quite some time on how to serialize a polymorphic data, and your question was informative enough to help me understand my error, and correct yours. Since your classes are not fully implemented I provide a code example that achieves what you want. In my example
#pragma once
#include <iostream>
#include <vector>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/iostreams/stream.hpp>
using namespace std;
class Parent; // Forward declares
class Child; // so my classes are in your order
Family is your LotsOfBases
class Family {
friend class boost::serialization::access;
public:
Family() { ; }
~Family() { ; }
vector<Parent*> m_members;
//////////////////////////////////////////////////////////////////////
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar.template register_type<Child>();
ar & m_members;
}
//////////////////////////////////////////////////////////////////////
};
Parent is your Base
class Parent {
friend class boost::serialization::access;
public:
Parent() : m_name("") { ; }
Parent(string name) : m_name(name) { ; }
~Parent() { ; }
virtual string GetName() { return m_name; }
private:
string m_name;
//////////////////////////////////////////////////////////////////////
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & m_name;
}
//////////////////////////////////////////////////////////////////////
};
Child is your Derived
class Child : public Parent {
friend class boost::serialization::access;
public:
Child() : Parent(), m_age(0) { ; }
Child(string name, int id) : Parent(name), m_age(id) { ; }
~Child() { ; }
int m_age;
private:
//////////////////////////////////////////////////////////////////////
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & boost::serialization::base_object<Parent>(*this);
ar & m_age;
}
//////////////////////////////////////////////////////////////////////
};
Main (for completeness)
int main() {
Child *timmy = new Child("Timmy", 4);
Family JohnsonFamily;
JohnsonFamily.m_members.push_back(timmy);
// serialize object into a std::string
std::string serial_str;
boost::iostreams::back_insert_device<std::string> inserter(serial_str);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string>> s(inserter);
boost::archive::binary_oarchive oa(s);
oa & JohnsonFamily;
s.flush();
// read object backout of standard string into new Family object
boost::iostreams::basic_array_source<char> device(serial_str.data(), serial_str.size());
boost::iostreams::stream<boost::iostreams::basic_array_source<char> > t(device);
boost::archive::binary_iarchive ia(t);
Family FosterFamily;
ia & FosterFamily;
auto baseptr = FosterFamily.m_members[0];
auto child = dynamic_cast<Child*>(baseptr);
if (child != nullptr) {
cout << "Derived type infered from serialized base pointer." << endl;
cout << child->GetName() << " is " << child->m_age << endl;
}
cin.get();
return 0;
}
I noticed that your Derived doesn't actually inherit, which is certainly causing issues. Also, the key point is that if you have a polymorphic container in a class, then you must register each derived type in the that class (not in the base class). See my Family class above.
Hope this helps you.
Upvotes: 3