2

I'm using this approach to serialize and deserialize a class hierarchy:

 // Enumeration of classes.
 struct Type {
     enum TypeEnum { A, B }
     TypeEnum t;
     Type(TypeEnum te) : t(te) { }
     bool operator == (TypeEnum te);
     void saveToStream(Stream& stream);
     void loadFromStream(Stream& stream);
 };

 // Serializable base class.
 struct A {
     Type type;
     A() { type = Type::A; }
     // ... members
     virtual void loadFromStream(Stream& stream);
     virtual void saveToStream(Stream& stream) const;
 };

 // Serializable child class.
 struct B : public A {
     B() : A() { type = Type::B; }
     virtual void loadFromStream(Stream& stream);
     virtual void saveToStream(Stream& stream);
 };

 // Helper class.
 struct Serializer {
     static A* loadFromStream(Stream& stream)
     {
        Type t;
        t.loadFromStream(stream);
        if (t == Type::A) {
           A* a = new A;
           a->loadFromStream(stream);
           return a;
        } else if (t == Type::B) {
           A* b = new B;
           b->loadFromStream(stream);
           return b;
        } 
        throw "Unknown type";
        return 0; // surpress warning
     }
     static void saveToStream(Stream& stream, const A& a)
     {
        a.type.saveToStream(stream);
        a.saveToStream(stream);
     }
 }; 

 // Usage
 B b;
 Serializer::saveToStream(stream, b);
 B* b2 = static_cast<B*>(Serializer::loadFromStream(stream));

This approach is pretty straightforward and simple to understand. But I was thinking about if there's a more elegant solution without the need to update class Type every time i expand the class hierarchy.

Do you have any hints how to do this without the enumerator class Type and maybe without the class Serializer?

WolfgangP
  • 3,195
  • 27
  • 37
  • Well, yeah, there are possibilities. You can do both static and dynamic registration, but the implementation really depends on where you want to put it. It can reside in the build system, it can be generated using macro/template meta-program or it can be even dynamic. – Šimon Tóth Nov 21 '10 at 20:34
  • Duplicate of http://stackoverflow.com/questions/4229748/pattern-for-delegation-to-sub-component/ ? – Ben Jackson Nov 21 '10 at 20:38

1 Answers1

2

This seems like a good candidate for a Factory Pattern.

Basically, it consists of delegating the responsibility of instantiating the correct type based on a given identifier. A search on Stack Overflow brought up this answer which provides a nice example of implementation in C++. Note that all objects that can be created by the factory must implement a common interface (which seems to be your case).

Once you implement this kind of pattern, you will be able to remove the if / else if cascade in Serializer::loadFromStream and just call loadFromStream on the factory instantiated object.

Community
  • 1
  • 1
icecrime
  • 74,451
  • 13
  • 99
  • 111
  • This is, by the way, the approach used by [QUiLoader](http://doc.qt.nokia.com/latest/quiloader.html) (although it serializes to XML, of course). – andref Mar 13 '11 at 20:00
  • Looking at the provided example i believe the `if/else if` cascade is a more straightforward approach and way easier to understand. – WolfgangP Apr 05 '11 at 18:33