c++ - 如何在从 QObject 派生的类上正确使用 qRegisterMetaType?

标签 c++ qt reflection

我一直在寻找答案,但无济于事。我的感叹如下:

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

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

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

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

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

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

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;
}

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

如果我们将类更改为如下所示:

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;
};

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

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 的指针。

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

最佳答案

一些事情:

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

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

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

  • 看看Qt对qMetaTypeConstructHelper的实现:

    template <typename T>
    void *qMetaTypeConstructHelper(const T *t)
    {
        if (!t)
            return new T();
        return new T(*static_cast<const T*>(t));
    }
    

并注意他们对复制构造函数的使用。在这种情况下,您有两种解决问题的方法:

1) 提供一个拷贝构造函数(你已经完成了)

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

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

关于c++ - 如何在从 QObject 派生的类上正确使用 qRegisterMetaType?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7872578/

相关文章:

c++ - OpenCV/FFMpeg图像捕捉问题

c++ - 字节 vector 转整数类型 : shift and add or implicit conversion through a union?

c++ - 常量引用 - C++

c++ - 在 C++ 中创建和显示十六进制字符串

JavaScript:Reflect.get() 和 obj ['foo' 之间的区别]

java - 我怎样才能找到一个字段(jackson)的 JSON 键?

c++ - 来自 cppreference.com 的模板参数特化示例不起作用

python - 在主窗口 PyQt 中处理关闭按钮的正确方法,(红色 "X")

java - Class.newInstance() 是否遵循 "Abstract factory"设计模式?

qt - 如何使用XQuery获取标签参数值