简体   繁体   English

QObject 派生的 class 的所有要求是什么?

[英]What are all the requirements of a QObject derived class?

I'm working on my first non-trivial project using the Qt Framework and to help maintain consistency across documents and to ensure I don't forget some small requirement I've decided to make a template document demonstrating the member functions, macros, etc. needed to subclass QObject.我正在使用 Qt 框架处理我的第一个重要项目,并帮助保持文档之间的一致性并确保我不会忘记一些小要求,我决定制作一个模板文档来展示成员函数、宏等. 需要继承 QObject。 I also want to be able to fully utilize the Meta Object system.我还希望能够充分利用 Meta Object 系统。 Am I missing anything or misunderstanding anything?我是否遗漏了什么或误解了什么? Also feel free to give any general C++ critiques as necessary.如有必要,也可以随意给予任何一般的 C++ 批评。

I'm especially concerned with the issue of whether or not to include a copy constructor.我特别关心是否包含复制构造函数的问题。 Is that only necessary for classes not derived from QObject?仅对于不是从 QObject 派生的类才需要吗?

Requirements (links are to the document I got the requirements from)要求(链接到我从中获得要求的文档)

  1. Public Default Constructor (link)公共默认构造函数(链接)
  2. Public Copy Constructor (see 1) (but conflicts with this)公共副本构造函数(参见 1) (但与此冲突)
  3. Public Destructor (see 1)公共析构函数(见 1)
  4. Use the Q_OBJECT Macro (link)使用 Q_OBJECT 宏(链接)
  5. Ensure Properties Are Accessible with the Q_PROPERTY(...) Macro (link)确保可以使用 Q_PROPERTY(...) 宏访问属性(链接)
  6. Declare the Type with Q_DECLARE_METATYPE(T) in the Header (link) (link)在 Header (link) (link)中用 Q_DECLARE_METATYPE(T) 声明类型
  7. Declare any Enums Used with Q_ENUM(E) in the Header (link)在 Header 中声明与 Q_ENUM(E) 一起使用的任何枚举(链接)

Template Header模板 Header

 // Include guards #ifndef CLASSNAME_H #define CLASSNAME_H // Include statements #include <QObject> #include <Th> // Enum definition enum E{ E0, E1, E2 }; // Q_ENUM Macro Q_ENUM(E) // Class declaration class ClassName: public QObject { // Q_OBJECT Macro Q_OBJECT // Q_PROPERTY Macros Q_PROPERTY(T* memberA READ memberA WRITE setMemberA NOTIFY memberAChanged) Q_PROPERTY(int memberB READ memberB WRITE setMemberB NOTIFY memberBChanged) Q_PROPERTY(E memberC READ memberC WRITE setMemberC RESET resetMemberC) public: // Constructors and Destructor ClassName(QObject *parent = nullptr); ClassName() = default; ClassName(const ClassName&) = default; ~ClassName(); // Getters T* memberA() const {return m_memberA;} int memberB() const {return m_memberB;} E memberC() const {return m_memberC;} // Setters void setMemberA(T* newA); void setMemberB(int newB); void setMemberC(E newC); signals: void memberAChanged(T*); void memberBChanged(int); public slots: void resetMemberC(); private slots: private: // Data Members T* m_memberA; int m_memberB; E m_memberC; }; // Meta Object Type Declaration Q_DECLARE_METATYPE(TypeName); // End include guard #endif // CLASSNAME_H

The source file to accompany this header would likely be trivial, so I won't include it here.伴随这个 header 的源文件可能是微不足道的,所以我不会在这里包含它。 Though if anyone thinks it would be helpful to demonstrate some requirement or functionality, I'd be happy to write it out.尽管如果有人认为演示某些要求或功能会有所帮助,我很乐意将其写出来。

As Jeremy Friesner suggested, the requirements are not that strict.正如 Jeremy Friesner 所建议的那样,要求并不那么严格。 The situation is more like this:情况更像是这样的:

  • If your class uses signals and/or slots, it must both have the Q_OBJECT macro and be derived from QObject,如果您的 class 使用信号和/或槽,它必须同时具有 Q_OBJECT 宏并从 QObject 派生,
  • If it only uses other meta-object functionality, such as Q_PROPERTY declarations, it can use the Q_GADGET macro and need not be derived from QObject,如果它只使用其他元对象功能,例如 Q_PROPERTY 声明,它可以使用 Q_GADGET 宏并且不需要从 QObject 派生,
  • If it doesn't need any of that, but should still be compatible with Qt templates like QVariant, it should be declared with Q_DECLARE_METATYPE.如果它不需要任何这些,但仍应与 QVariant 等 Qt 模板兼容,则应使用 Q_DECLARE_METATYPE 声明。 The same applies to enums and Q_ENUM.这同样适用于枚举和 Q_ENUM。

A Q_PROPERTY/Q_INVOKABLE interface is only really needed if you need your class to be interoperable with QML code.只有当您需要 class 与 QML 代码互操作时,才真正需要 Q_PROPERTY/Q_INVOKABLE 接口。

As for your other question, yes that is an important difference between QObjects and non-QObjects.至于您的另一个问题,是的,这是 QObjects 和非 QObjects 之间的重要区别。 The metatype must be copyable, which is why that is required of types you manually declare as metatypes, and also why the system instead uses pointers for QObject types, which are not copyable themselves.元类型必须是可复制的,这就是您手动声明为元类型的类型需要这样做的原因,也是系统改为使用 QObject 类型指针的原因,这些指针本身不可复制。 A minimal QObject declaration could start like this:一个最小的 QObject 声明可以这样开始:

 #ifndef CLASSNAME_H #define CLASSNAME_H #include <QObject> // Enums in the global namespace cannot be registered; they must be enclosed // in a class and registered with Q_ENUM, or in a namespace declared as // Q_NAMESPACE and registered with Q_ENUM_NS class ClassName: public QObject { Q_OBJECT public: // Default constructor, with explicit specifier to prevent accidental // implicit conversion from a QObject* explicit ClassName(QObject *parent = nullptr); }; // ClassName* is automatically declared as a metatype #endif // CLASSNAME_H

In general I'd recommend the " rule of zero ": if possible, do not declare a destructor, nor any copy and move operations, and leave them to the compiler.一般来说,我推荐“ 零规则”:如果可能,不要声明析构函数,也不要声明任何复制和移动操作,并将它们留给编译器。 Of course I also recommend all of the other guidelines there, if you have the time当然,如果您有时间,我也推荐那里的所有其他指南

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM