c++ – How to properly use qRegisterMetaType on a class derived from QObject?

c++ – How to properly use qRegisterMetaType on a class derived from QObject?

A few things:

  • The reason that registering ClassA* isnt working is because your call to construct() is constructing a pointer to a ClassA object, but not an actual object.
  • It is worthy of noting the following quote from the QMetaType documentation:

Any class or struct that has a public default constructor, a public
copy constructor, and a public destructor can be registered.

  • Take a look at Qts implementation of qMetaTypeConstructHelper:
    template <typename T>
    void *qMetaTypeConstructHelper(const T *t)
    {
        if (!t)
            return new T();
        return new T(*static_cast<const T*>(t));
    }
    

and note their usage of the copy constructor. This being the case, you have two ways around the problem:

1) Provide a copy constructor (which you have done)

2) Provide a specialization of qMetaTypeConstructHelper that doesnt use the copy constructor:

template <>
void *qMetaTypeConstructHelper<ClassA>(const ClassA *)
{
    return new ClassA();
}

If you want to create instances of QObject classes by name, you can use QMetaObject instead of QMetaType.

First, you have to declare your constructor as invokable:

class ClassA : public QObject {
    Q_OBJECT
public:
    Q_INVOKABLE ClassA() { mName = lol; }
    ~ClassA();
    void showName() { std::cout << mName << std::endl; }
    std::string mName;
};

Then you have to create your own registration system for the classes you want to instantiate, and populate it manually:

int main(int argc, char *argv[])
{    
    // Register your QObject derived classes
    QList<const QMetaObject*> metaObjectList;
    metaObjectList << &ClassA::staticMetaObject;

    // Index the classes/metaobject by their names
    QMap<QString, const QMetaObject*> metaObjectLookup;
    foreach(const QMetaObject *mo, metaObjectList) {
        metaObjectLookup.insert(mo->className(), mo);
    }

And finally youll be able instantiate by name any registered class:

    const QMetaObject * myMetaObject = metaObjectLookup.value(ClassA, 0);
    if(!myMetaObject)
    {
        // The class doesnt exist
        return 1;
    }

    ClassA *myObject =
            static_cast<ClassA*>(myMetaObject->newInstance());
    if(!myObject)
    {
        // Couldnt create an instance (constructor not declared Q_INVOKABLE ?)
        return 1;
    }
    myObject->showName();

    return 0;
}

c++ – How to properly use qRegisterMetaType on a class derived from QObject?

Heres an update to Chris solution #2 for Qt 5:

namespace QtMetaTypePrivate {
    template <>
    struct QMetaTypeFunctionHelper<ClassA, true> {
        static void Delete(void *t)
        {
            delete static_cast<ClassA*>(t);
        }

        static void *Create(const void *t)
        {
            Q_UNUSED(t)
            return new ClassA();
        }

        static void Destruct(void *t)
        {
            Q_UNUSED(t) // Silence MSVC that warns for POD types.
            static_cast<ClassA*>(t)->~ClassA();
        }

        static void *Construct(void *where, const void *t)
        {
            Q_UNUSED(t)
            return new (where) ClassA;
        }
    #ifndef QT_NO_DATASTREAM
        static void Save(QDataStream &stream, const void *t)
        {
            stream << *static_cast<const ClassA*>(t);
        }

        static void Load(QDataStream &stream, void *t)
        {
            stream >> *static_cast<ClassA*>(t);
        }
    #endif // QT_NO_DATASTREAM
    };
}

If your ClassA doesnt implement operator<< and operator>> helpers for QDataStream, comment out the bodies of Save and Load or youll still have a compiler error.

Leave a Reply

Your email address will not be published.