Reputation: 612
New: Can I use this, from access.hpp?
template<class Archive, class T>
inline void serialize_adl(Archive &, T &, const unsigned int);
This suggests that I can define a different serialize that takes the object as a parameter.
Thus would this code change below work?
I think my question is how do I add a serialize method on an interface class, which will invoke the serialize method on the derived sub-class.
class Interface {
public:
virtual void aVirtual() = 0;
private:
friend class boost::serialization::access;
template<class Archive, class T>
void serialize_adl(Archive & ar, T & object, const unsigned int version)
{
// Would this work?????
ar & object;
}
};
template<class T>
class Derived : Interface {
public:
Derived(T in) : m_data(in) {}
virtual void aVirtual() { // Do something }
private:
T m_data;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & m_data;
}
};
I currently get the following error from my compiler:
error C2039: 'serialize' : is not a member of 'Interface'
which is unusual because the object is inside a smart pointer, so it should know what type it is:
std::unique_ptr<Interface> object = std::unique_ptr<Interface>(new Derived<int>(5));
And thus when I try to serialise:
archive >> *object;
Thus I get the error.
Upvotes: 3
Views: 2259
Reputation: 392833
There's two issues at play here:
You are serializing a template class. This is not a problem and yes you can do this intrusively (member serialize
) or non-intrusively (free function serialize
via ADL). As the documentation (Serializing Templates) states the implementation of shared_ptr<T>
serialization is a good example of the non-intrusive variant here:
You are serializing base/derived classes through a polymorphic pointer. For the serialization part this is nothing special (you can register_type
or you should be fine using base_object<Interface>(this)
inside the derived's serialize
function.
On the deserialization side of things, however, you need to anticipate the full list of possible concrete instance types serialized through the polymorphic pointer. The BOOST_EXPORT_CLASS
macro is the easiest way to achieve this. You will have to list the concrete instances of the template you wish to support, though:
BOOST_CLASS_EXPORT(Derived<std::string>)
BOOST_CLASS_EXPORT(Derived<double>)
BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
or
BOOST_CLASS_EXPORT_GUID(Derived<std::string>, "4ef5a3ff-168a-4242-846b-4886f48424b5")
BOOST_CLASS_EXPORT_GUID(Derived<double>, "d0ed9de6-584f-476d-9898-8234bcb4efdb")
BOOST_CLASS_EXPORT_GUID(Derived<int>, "505538f0-2dd1-43bd-92a2-506ed9659bbe") // include all subtypes we can expect in an input archive
The complexity of the situation - and the confusion - arises from the fact that you are serializing a derived class template through a polymorphic pointer. All at the same time. But conceptually both are easily tackled.
Slightly unrelated,
- Yes, you can use free function serialize, see the 3rd alternative version below. It gains you little though, and just requires
m_data
to be publicly accessible.- Do not use
serialize_adl
as it is an implementation detail
Here are three samples that integrates everything:
Live On Coliru - raw Interface*
Live On Coliru - same with shared_ptr<Interface>
Live On Coliru - same with non-intrusive serialize
function
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <sstream>
class Interface {
public:
virtual void aVirtual() = 0;
virtual ~Interface() {}
private:
friend class boost::serialization::access;
template<class Archive> void serialize(Archive&, unsigned) { }
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Interface)
template<class T>
class Derived : public Interface {
public:
Derived(T in = 0) : m_data(in) {}
virtual void aVirtual() { /*Do something*/ }
T const& getData() const { return m_data; }
private:
T m_data;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive& ar, unsigned)
{
ar & boost::serialization::base_object<Interface>(*this);
//// alternatively, if you don't want to make the abstract base serializable:
// boost::serialization::void_cast_register<Derived, Interface>();
ar & m_data;
}
};
BOOST_CLASS_EXPORT(Derived<std::string>)
BOOST_CLASS_EXPORT(Derived<double>)
BOOST_CLASS_EXPORT(Derived<int>) // include all subtypes we can expect in an input archive
int main()
{
std::stringstream ss;
{
boost::archive::text_oarchive oa(ss);
Interface* o = new Derived<int>(42);
oa << o;
delete o;
}
std::cout << "Serialized: '" << ss.str() << "'\n";
{
boost::archive::text_iarchive ia(ss);
Interface* o = nullptr;
ia >> o;
if (auto p = dynamic_cast<Derived<int>*>(o))
std::cout << "Deserialized into Derived<int> with data: " << p->getData() << "\n";
delete o;
}
}
Sample output:
Serialized: '22 serialization::archive 11 0 1 1 12 Derived<int> 1 0
0 42
'
Deserialized into Derived<int> with data: 42
Upvotes: 4
Reputation: 1
You should serialize only the derived object. use dynamic_cast for Type conversion
class Interface {
virtual void f() = 0;
};
template<class T> class Derived : public Interface {
T m_data; void f(){};
};
Interface* object = new Derived<Type>();
Derived<Type>* objectSer = dynamic_cast<Derived<Type>*>(object);
//serialization
std::ofstream ofs("filename");
boost::archive::text_oarchive oa(ofs); oa << *objectSer;
Upvotes: -1
Reputation: 63
Well, maybe this could help you or i could be wrong; but in c++ inherit, There is not a mechanism for to make call to subclass's methods, because a class can to have many subclass and the superclass have not the subclass's reference, because the polymorphism function from subclass to superclass and not in mode inverse. for that reason, you can call a superclass's function since the derived class.
best regards.
Upvotes: 0