boost serialization of derived object doesn't call derived's serialize()
Asked Answered
G

3

6

I've read through loads of similar questions but haven't found the answer. I'm using Visual Studio 2010 and boost 1.47.

Here's the code, it's complete and compilable:

#include "stdafx.h"

#include <string>
#include <sstream>

#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

#include <boost/serialization/export.hpp>

using namespace std;

class BaseObject 
{
public:

    BaseObject(void) { };
    virtual ~BaseObject(void) { };

    template<class Archive>
      void serialize(Archive &ar, const unsigned int version)
      { /* nothing happens here */  };
};

class DerivedObject : public BaseObject
{
public:

    string text;

public:

    DerivedObject(void) { };
    ~DerivedObject(void) { };

    template<class Archive>
      void serialize(Archive &ar, const unsigned int version)
      {
          ar & text;
      };
};

BOOST_CLASS_EXPORT(DerivedObject)

int _tmain(int argc, _TCHAR* argv[])
{
    DerivedObject der;
    der.text = "Testing!";

    std::ostringstream os;
    boost::archive::text_oarchive oa(os);
    oa.register_type<DerivedObject>();

    // I made a DerivedObject, but I'm casting it to a BaseObject
    // as the serialization code should not have to know what type it is
    BaseObject *base = &der;
    // now serialize it
    oa << *base;

    printf("serialized: %s\r\n",os.str().c_str()); 

    return (0);
}

You can see it's real simple, and I've added the BOOST_CLASS_EXPORT and oa.register_type magic that's supposed to make sure DerivdObject::serialize() is called even though it isn't a virtual method.. but still only serialize() in BaseObject is called. A problem specific to Visual C++ perhaps? Please advice?

Glassworker answered 15/3, 2012 at 10:41 Comment(2)
Shouldn't your BaseObject::serialize be marked as virtual?Rincon
Good point - didn't notice the template bit!Rincon
I
2

As described in the boost serialization documentation you need to tell your derived class to call the base class serialization code. Just write your derived class serialize method like this :

  template<class Archive>
  void serialize(Archive &ar, const unsigned int version)
  {
      ar & boost::serialization::base_object<BaseObject>(*this);
      ar & text;
  };
Invertase answered 28/3, 2013 at 11:53 Comment(0)
M
0

I haven't tried this out in the debugger or anything, but it looks like it might be a case of slicing. Perhaps you could find out by modifying your code to serialize by pointer or by reference instead of by value, like so...

BaseObject *base = &der;
oa << base;  // Serialize a pointer

...or...

BaseObject& base = der;
oa << base;  // Serialize a reference
Michaelamichaele answered 16/3, 2012 at 6:15 Comment(2)
Thanks, but the first one throws an exception, unregistered class something, and the other one does basically the same thing as my code. Same result...Glassworker
I realized afterwards that the << operator probably takes the argument by reference anyway, which makes my theory completely wrong. Sorry. Have you tried registering the base class? I'm using this stuff on a current project at work, but all the details were set up by someone else, so I'm not entirely clear on the setup portion. :/Michaelamichaele
G
0

This is not strictly an answer, just a kludgy workaround.

In the base class add:

virtual void StreamToArchive(boost::archive::text_oarchive &oa) = 0;

then define a macro STREAMTOARCHIVE and put it to each and every one of the derived classes.

#define STREAMTOARCHIVE void StreamToArchive(boost::archive::text_oarchive &oa) { oa << *this; }

Then in main, replace

oa << base;

with

base.StreamToArchive(oa);

Yea I know, it's ugly, but.. well it works and I just have to put that STREAMTOARCHIVE macro in the derived classes... I can live with that...

But then... to parse it back into an object, now that's another matter...

Edited: changed 'this' to '*this'

Glassworker answered 16/3, 2012 at 21:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.