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

前端 未结 3 1583
南方客
南方客 2020-12-08 15:09

I\'ve been searching far and wide for an answer to this but to no avail. My lament is as follows:

I have a ClassA that roughly looks like this:

相关标签:
3条回答
  • 2020-12-08 15:31

    A few things:

    • The reason that registering ClassA* isn't 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 Qt's 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 doesn't use the copy constructor:

    template <>
    void *qMetaTypeConstructHelper<ClassA>(const ClassA *)
    {
        return new ClassA();
    }
    
    0 讨论(0)
  • 2020-12-08 15:34

    Here's 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 doesn't implement operator<< and operator>> helpers for QDataStream, comment out the bodies of Save and Load or you'll still have a compiler error.

    0 讨论(0)
  • 2020-12-08 15:43

    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 you'll be able instantiate by name any registered class:

        const QMetaObject * myMetaObject = metaObjectLookup.value("ClassA", 0);
        if(!myMetaObject)
        {
            // The class doesn't exist
            return 1;
        }
    
        ClassA *myObject =
                static_cast<ClassA*>(myMetaObject->newInstance());
        if(!myObject)
        {
            // Couldn't create an instance (constructor not declared Q_INVOKABLE ?)
            return 1;
        }
        myObject->showName();
    
        return 0;
    }
    
    0 讨论(0)
提交回复
热议问题