PDA

View Full Version : Serialization and inheritance using Qt



totem
16th January 2011, 12:55
I have an inheritance tree like :


BaseClass : QObject {
Q_OBJECT
// etc..
} ;

ChildClass1 : BaseClass {
Q_OBJECT
// etc..
} ;

ChildClass2 : BaseClass {
Q_OBJECT
// etc..
} ;

And for each class I declared and defined default constructor, copy constructor, assignment operator overload, and friend << and >> operators for QDataStream support.

Now, I have a list of BaseClass pointers used as follow :


void saveData(QDataStream & stream)
{
QList<BaseClass*> objList ;
objList.append( new ChildClass1() ) ;
objList.append( new ChildClass2() ) ;
stream << objList.length() ;
foreach(BaseClass *obj, objList)
{
stream << (*obj) ;
}
}


So when I serialize this list, how do I make sure it's actually ChildClass1 or ChildClass2 instances beeing serialized ? stream operators are non-member functions, so they cannot be virtual.

The same way when I de-serialize objects, (I must be blind but) I'm stuck with the following :

void readData(QDataStream & stream)
{
int i, count ;
QList<BaseClass*> someList ;
stream >> count ;
for(i=0; i<count; i++)
{
stream >> ...// now what do I do here ?
}
}


Long story short, how do I combine Qt serialization and class inheritance ?

Any pointer would be greatly appreciated

tbscope
16th January 2011, 13:08
The object list in your saveData function should not be needed. QObject keeps a list for you already. Just set the correct parent when creating a child. This makes the code a bit nicer.

As for the serialization. The key is to understand which data belongs to which type of class and which item is a parent or child.
I personally like xml for this. Example:

When I have the following parent/child tree:


ParentItem1 of Type1
ChildItem1 of Type2
ChildItem2 of Type3

I can save the data like this

<item type="Type1" value1="someValueSpecificForType1Objects">
<item type="Type2" value1="someValueSpecificForType2Objects"/>
<item type="Type3" value1="somethingElseEtc"/>
</item>
The style of the xml tree is of course personal taste.

Now, to read this structure back pass the data to the base class and let it create its childs and set the data and pass along the information destined for the children to the child objects so they can do the same.
You also might want to create a factory if the base class is not always of the same type.

Edit: this is of course without a qdatastream.
Note that a QDataStream isn't very flexible. You'll probably need a lot of support code to read and create the child objects (decoding) while it would be trivial with a xml reader/writer

high_flyer
16th January 2011, 14:24
So when I serialize this list, how do I make sure it's actually ChildClass1 or ChildClass2 instances beeing serialized ?
one way is to have the base class declare an 'm_type' variable (an enum would be convenient) that the inheriting classes must define - which you then can ask for and based on the type make the correct cast.
Once the pointer is casted, the correct stream operator will be used automatically.

totem
16th January 2011, 14:34
@tbscope : thank you for your suggestions. However, I want to keep the QDataStream support; if i'm right it will also open me doors of drag/drop support

@high_flyer : I do have this system, so I will use the solution to switch on object->type() and instanciate DerivedClass accordingly. It's inelegant :) but if it works...

wysota
16th January 2011, 16:00
@tbscope : thank you for your suggestions. However, I want to keep the QDataStream support; if i'm right it will also open me doors of drag/drop support
Using QDataStream instead of any other serialization form doesn't help in any way to handle drag&drop. In either case you end up with a block of bytes, it's just a matter of which mechanism populates the blob but nothing happens on its own, you have to write code that does it yourself.

If you want to use QDataStream in this specific case then your base-class has to know all its potential subclasses and handle conversions between them and itself. This is of course possible but it's quite a lot of work so if you don't feel comfortable with the topic, I wouldn't recommend this approach.

totem
16th January 2011, 16:16
Using QDataStream instead of any other serialization form doesn't help in any way to handle drag&drop
Yes I'm sorry. I meant I want to be able to use these classes with qRegisterMetaTypeStreamOperators(), I use it for drag/drop.


If you want to use QDataStream in this specific case then your base-class has to know all its potential subclasses
My project is not that huge, it's a matter of a dozen classes for now.
I was just wondering if there existed elegant C++/Qt solution with QDataStream serialization and inheritance.

Thank you all for your answers