Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you 'de-serialize' a derived class from serialized data?

How do you 'de-serialize' a derived class from serialized data? Or maybe I should say, is there a better way to 'de-serialize' data into derived classes?

For example, suppose you had a pure virtual base class (B) that is inherited by three other classes, X, Y and Z. Moreover, we have a method, serialize(), that will translate X:B, Y:B and Z:B into serialized data.

This way it can be zapped across a socket, a named pipe, etc. to a remote process.

The problem I have is, how do we create an appropriate object from the serialized data?

The only solution I can come up with is including an identifier in the serialized data that indicates the final derived object type. Where the receiver, first parses the derived type field from the serialized data, and then uses a switch statement (or some sort of logic like that) to invoke the appropriate constructor.

For example:

B deserialize( serial_data )
{
    parse the derived type from the serial_data

    switch (derived type)
        case X
            return X(serial_data)
        case Y
            return Y(serial_data)
        case Z
            return Z(serial_data)
}

So after learning the derived object type we invoke the appropriate derived type constructor.

However, this feels awkward and cumbersome. I'm hoping there is a more eloquent way of doing this. Is there?

like image 948
John Rocha Avatar asked Jul 16 '10 20:07

John Rocha


People also ask

Which one is correct class for JsonSerializer?

The JsonSerializer is a static class in the System. Text. Json namespace. It provides functionality for serializing objects to a JSON string and deserializing from a JSON string to objects.

What does serialize deserialize mean?

Serialization is a mechanism of converting the state of an object into a byte stream. Deserialization is the reverse process where the byte stream is used to recreate the actual Java object in memory. This mechanism is used to persist the object. The byte stream created is platform independent.

What is Jsonconvert SerializeObject C#?

SerializeObject Method (Object, Type, JsonSerializerSettings) Serializes the specified object to a JSON string using a type, formatting and JsonSerializerSettings.

How do you serialize class?

For serializing the object, we call the writeObject() method of ObjectOutputStream class, and for deserialization we call the readObject() method of ObjectInputStream class. We must have to implement the Serializable interface for serializing the object. Video Player is loading.


1 Answers

In fact, it's a more general issue than serialization called Virtual Constructor.

The traditional approach is to a Factory, which based on an ID returns the right derived type. There are two solutions:

  • the switch method as you noticed, though you need to allocate on the heap
  • the prototype method

The prototype method goes like so:

// Cloneability
class Base
{
public:
  virtual Base* clone() const = 0;
};

class Derived: public Base
{
public:
  virtual Derived* clone() const { return new Derived(*this); }
};

// Factory
class Factory
{
public:
  Base* get(std::string const& id) const;
  void set(std::string const& id, Base* exemplar);

private:
  typedef std::map < std::string, Base* > exemplars_type;
  exemplars_type mExemplars;
};

It is somewhat traditional to make the Factory a singleton, but it's another matter entirely.

For deserialization proper, it's easier if you have a virtual method deserialize to call on the object.

EDIT: How does the Factory work ?

In C++ you can't create a type you don't know about. The idea above is therefore that the task of building a Derived object is given to the Derived class, by way of the clone method.

Next comes the Factory. We are going to use a map which will associate a "tag" (for example "Derived") to an instance of an object (say Derived here).

Factory factory;
Derived derived;
factory.set("Derived", &derived);

Now, when we want to create an object which type we don't know at compile time (because the type is decided on the fly), we pass a tag to the factory and ask for an object in return.

std::unique_ptr<Base> base = factory.get("Derived");

Under the cover, the Factory will find the Base* associated to the "Derived" tag and invoke the clone method of the object. This will actually (here) create an object of runtime-type Derived.

We can verify this by using the typeid operator:

assert( typeid(base) == typeid(Derived) );
like image 74
Matthieu M. Avatar answered Oct 22 '22 10:10

Matthieu M.