如何在从 QObject 派生的类上正确使用 qRegisterMetaType? [英] How to properly use qRegisterMetaType on a class derived from QObject?

查看:45
本文介绍了如何在从 QObject 派生的类上正确使用 qRegisterMetaType?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在四处寻找答案,但无济于事.我的哀叹如下:

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

我有一个 ClassA 大致如下所示:

I have a ClassA that roughly looks like this:

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

当然,因为我使用的是moc,这个类在我的项目中实际上分为cpp和hpp,但这部分不是这里的问题.

Of course, since I use moc, this class is actually split into cpp and hpp in my project but that part is not the issue here.

请注意,我并没有故意使用 Q_DECLARE_METATYPE,因为我现在实际上并不需要它的功能(QVariant 扩展).我只关心运行时实例化.

Please note that I do not use Q_DECLARE_METATYPE on purpose because I don't actually need its features (QVariant expansion) right now. I only care about runtime instantiation.

这里的问题是 Q_OBJECT 禁止复制和赋值构造函数.因此,我必须将 qRegisterMetaType 应用到 ClassA 本身而不是 ClassA* 乍一看似乎工作正常.

The issue here is that Q_OBJECT forbids the copy and assignment constructors. Due to that, I have to apply qRegisterMetaType not to ClassA itself but to ClassA* which seems to work fine at first glance.

现在,我想在运行时从字符串动态创建这个类并运行方法 ShowName().我是这样做的:

Now, I want to create this class dynamically at runtime from a string and run the method ShowName(). I'm doing that like this:

int main() {
    qRegisterMetaType<ClassA*>("ClassA*");

    int id = QMetaType::type("ClassA*");
    std::cout << "meta id: " << id << std::endl; // Outputs correct generated user id (not 0)

    ClassA* myclass = static_cast<ClassA*>(QMetaType::construct(id));
    myclass->ShowName(); // Segfaults, oh dear

    return 0;
}

现在是我的问题.我似乎实际上没有正确构造的对象.

Now, there is my issue. I don't seem to actually have a correctly constructed object there.

如果我们把类改成这样:

If we change the class to look like this:

class ClassA : public QObject {
    Q_OBJECT
public:
    ClassA() { mName = "lol"; }
    ClassA(const ClassA& other) { assert(false && "DONT EVER USE THIS"); }
    ~ClassA();
    void ShowName() { std::cout << mName << std::endl; }
    std::string mName;
};

然后我们可以相应地更改我们的程序:

then we can change our program accordingly to:

int main() {
    qRegisterMetaType<ClassA>("ClassA");

    int id = QMetaType::type("ClassA");
    std::cout << "meta id: " << id << std::endl; // Outputs correct generated user id (not 0)

    ClassA* myclass = static_cast<ClassA*>(QMetaType::construct(id));
    myclass->ShowName(); // "lol", yay

    return 0;
}

显然我可以只使用我伪造的覆盖复制构造函数,但感觉不对,Qt 建议反对,而是建议仅使用指向 QObjects 的指针.

Obviously I could just use my fake overwritten copy constructor but it doesn't feel right and Qt suggests against that and instead suggests the use of pointers to QObjects only.

有人看到这里出了什么问题吗?另外,我知道在 SO 上有类似的问题,但没有一个解决这个确切的问题.

Does anyone see what's wrong here? Also, I am aware there are similar questions on SO but none of them tackle this exact problem.

推荐答案

一些事情:

  • 注册 ClassA* 不起作用的原因是您对construct() 的调用正在构造一个指向ClassA 对象的指针,而不是一个实际的对象.

  • 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.

值得注意的是 QMetaType 文档中的以下引用:

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.

  • 看看Qt对qMetaTypeConstructHelper的实现:

    • 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) 提供一个复制构造函数(你已经完成了)

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

      2) 提供不使用复制构造函数的 qMetaTypeConstructHelper 的特化:

      2) Provide a specialization of qMetaTypeConstructHelper that doesn't use the copy constructor:

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

      这篇关于如何在从 QObject 派生的类上正确使用 qRegisterMetaType?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆