Question

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.

Était-ce utile?

La solution

There's two issues at play here:

  1. 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:


  2. 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:

  1. Live On Coliru - raw Interface*

  2. Live On Coliru - same with shared_ptr<Interface>

  3. Live On Coliru - same with non-intrusive serialize function

Listing for the first sample

#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

Autres conseils

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.

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; 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top