Skip to content
This repository has been archived by the owner on Mar 4, 2023. It is now read-only.

Polymorphic Q_GADGETs #8

Closed
arietto opened this issue Jun 29, 2018 · 3 comments
Closed

Polymorphic Q_GADGETs #8

arietto opened this issue Jun 29, 2018 · 3 comments
Assignees

Comments

@arietto
Copy link

arietto commented Jun 29, 2018

Hello! Do you have any hints concerning (de-)serialization of polymorphic Q_GADGETs? They can also have Q_CLASSINFO. I suppose that I have to create a "switch" for property getter/setter which checks some flag in JSON. It will choose, in fact, among variant.value<Class1>(), variant.value<Class2>() and so on for deserialization.

@Skycoder42 Skycoder42 self-assigned this Jun 29, 2018
@Skycoder42
Copy link
Owner

With the current implementation, this is not directly possible. The reason is that gadgets are value types and c++ can simply not handle polymorphism for value types correctly. Also, gadgets do not have a non-static metaobject associated, which means it's impossible to dynamically detect their type.

However, if you are fine with a workaround, I guess the following would work:

Assuming you have the following (simplified) classes:

class GadgetBase {
    //...
};

class Gadget1 : public GadgetBase {
    // ...
};

class Gadget2 : public GadgetBase {
    // ...
};

class SomeOtherGadget {
    GadgetBase *theGadget; //should be either 1 or 2
};

You could implement SomeOtherGadget as follows:

class SomeOtherGadget {
    Q_GADGET

    Q_PROPERTY(QJsonObject theGadget READ getGad WRITE setGad)

    GadgetBase *theGadget;
    QJsonSerializer *serializer;

    SomeOtherGadget() {
        serializer = // get the serializer somehow or just create a new one
    }

    QJsonObject getGad() const {
        QJsonObject obj;
        QString type = getGadgetClassName(theGadget);
        if(type == "Gadget1")
            obj = serializer->serialize(*static_cast<Gadget1*>(theGadget));
        else if(type == "Gadget2")
            obj = serializer->serialize(*static_cast<Gadget2*>(theGadget));
        // ...
        obj["@class"] = type;
        return obj;
    }

    void setGad(const QJsonObject &obj) {
        if(obj["@class"] == "Gadget1")
            theGadget = new Gadget1(serializer->deserialize<Gadget1>(obj)); //copy-construct to the heap
        else if(obj["@class"] == "Gadget2")
            theGadget = new Gadget2(serializer->deserialize<Gadget2>(obj)); //copy-construct to the heap
        // ...
    }
};

It's a little complicated and verbose, but more or less the only way to make gadget serialization "polymorphic" (I used a special property name @class here to keep the same syntax in JSON as the QObject based classes. But you can of course store that information however you like). I hope this can help you

@Skycoder42
Copy link
Owner

Another alternative would be to implement a custom QJsonTypeConverter that does more or less the same thing. If you have many classes that need this polymorphism, using a custom converter would be much more convenient I guess.

@arietto
Copy link
Author

arietto commented Jul 2, 2018

Thank you for your huge reply. I suppose that you code sample will be helpful for other users too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants