Qt源码解析之QObject
省去大部分virtual和public方法后,Qobject主要剩下以下成员:
//qobject.h class Q_CORE_EXPORT Qobject{ Q_OBJECT Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged) Q_DECLARE_PRIVATE(QObject) public: Q_INVOKABLE explicit QObject(QObject *parent=nullptr); virtual ~QObject(); //... protected: QObject(QObjectPrivate &dd, QObject *parent = nullptr); //... protected: QScopedPointer d_ptr; static const QMetaObject staticQtMetaObject; //... private: Q_DISABLE_COPY(QObject) //... }
一、Q_OBJECT
#define Q_OBJECT \ public: \ QT_WARNING_PUSH \ Q_OBJECT_NO_OVERRIDE_WARNING \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ virtual int qt_metacall(QMetaObject::Call, int, void **); \ QT_TR_FUNCTIONS \ private: \ Q_OBJECT_NO_ATTRIBUTES_WARNING \ Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \ QT_WARNING_POP \ struct QPrivateSignal {}; \ QT_ANNOTATE_CLASS(qt_qobject, "") 1、宏 QT_WARNING_PUSH 和 QT_WARNING_POP用于保存和恢复编译器的警告状态,以便在宏定义内部做一些修改或设置,而不影响用户定义的警告状态。 2、Q_OBJECT_NO_OVERRIDE_WARNING和Q_OBJECT_NO_ATTRIBUTES_WARNING这两个宏用于控制是否发出关于未覆盖(override)的警告或者关于某些属性的警告。 3、QT_TR_FUNCTIONS这个宏用于启用Qt的国际化(internationalization)功能,使得文本可以被翻译为不同的语言。 4、Q_DECL_HIDDEN_STATIC_METACALL在qobjectdefs.h有定义: # define Q_DECL_HIDDEN_STATIC_METACALL Q_DECL_HIDDEN 使用 Q_DECL_HIDDEN 可以将类或函数标记为在外部接口中隐藏的,从而使它们对库的用户不可见。这对于避免一些链接时的符号冲突和提高库的封装性很有帮助。这个宏可能会被翻译成 __attribute__((visibility("hidden")))。也就是说qt_static_metacall这个函数没用到,我们忽略。
去除和编译器相关的宏,Q_OBJECT剩下的关键部分:
//qobjectdefs.h #define Q_OBJECT \ public: \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ virtual void *qt_metacast(const char *); \ virtual int qt_metacall(QMetaObject::Call, int, void **); \ private: \ Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); Q_OBJECT宏声明了1个QMetaObject变量和3个QMetaObject相关的虚函数。QMetaObject类非常重要,和元对象系统相关。
二、Q_PROPERTY
//qobjectdefs.h #define Q_PROPERTY(...) QT_ANNOTATE_CLASS(qt_property, __VA_ARGS__) #define QT_ANNOTATE_CLASS(type, ...) 在 qobjectdefs.h 中我们并没有看到 Q_PROPERTY 的准确定义。很多Qt的宏和特殊功能是通过moc生成的代码而不是在头文件中显式定义的。C++编译器能够识别 Q_PROPERTY 宏,是因为moc编译时生成了相应的代码。 使用Q_PROPERTY后,相当于把属性纳入了元对象系统,而且给出了一段Q_PROPERTY更细致的声明: Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction | WRITE setFunction)]) [RESET resetFunction] [NOTIFY notifySignal] [REVISION int | REVISION(int[, int])] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [BINDABLE bindableProperty] [CONSTANT] [FINAL] [REQUIRED])
三、Q_DECLARE_PRIVATE
//qglobal.h #define Q_DECLARE_PRIVATE(Class) \ inline Class##Private* d_func() \ { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ inline const Class##Private* d_func() const \ { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } \ friend class Class##Private; 加入参数并翻译过后: inline QObjectPrivate* d_func() { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } inline const QObjectPrivate* d_func() const { Q_CAST_IGNORE_ALIGN(return reinterpret_cast(qGetPtrHelper(d_ptr));) } friend class QObjectPrivate; qGetPtrHelper()方法的定义: //qglobal.h template static inline T *qGetPtrHelper(T *ptr) { return ptr; } template static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); } qGetPtrHelper是一个模板函数,其目的是为了获取指针或类似指针的数据。 Q_CAST_IGNORE_ALIGN用于禁用GCC编译器的 -Wcast-align 警告。 Q_DECLARE_PRIVATE宏定义了2个函数和1个友元类。2个d_func只是签名不同,传入参数d_ptr,都返回一个QObjectPrivate*类型的指针,而且友元类的名称也是QObjectPrivate。
四、QObjectData和QObjectPrivate
关于变量QScopedPointer d_ptr: QScopedPointer类是用于存储指向动态分配对象的指针,并在其销毁时删除它,确保指向的对象在当前作用域消失时将被删除。 所以QScopedPointer是一个QObjectData的指针。 QObjectData定义: //qobject.h class Q_CORE_EXPORT QObjectData { //防止对象拷贝 Q_DISABLE_COPY(QObjectData) public: QObjectData() = default; virtual ~QObjectData() = 0; QObject *q_ptr; QObject *parent; QObjectList children; uint isWidget : 1; uint blockSig : 1; uint wasDeleted : 1; uint isDeletingChildren : 1; uint sendChildEvents : 1; uint receiveChildEvents : 1; uint isWindow : 1; //for QWindow uint deleteLaterCalled : 1; uint unused : 24; int postedEvents; QDynamicMetaObjectData *metaObject; QMetaObject *dynamicMetaObject() const; #ifdef QT_DEBUG enum { CheckForParentChildLoopsWarnDepth = 4096 }; #endif }; 上面说到d_func函数传入参数d_ptr,返回的QObjectPrivate*类型的指针,而d_ptr是QObjectData,那也就是说QObjectPrivate是QObjectData的子类。我们且看QObjectPrivate的定义: //qobject_p.h class Q_CORE_EXPORT QObjectPrivate : public QObjectData { Q_DECLARE_PUBLIC(QObject) public: struct ExtraData{ //... }; //和信号&槽相关 struct ConnectionOrSignalVector{ //... }; //和信号&槽相关 struct Connection : public ConnectionOrSignalVector{ //... }; //和信号&槽相关 struct Sender{ //... }; //和信号&槽相关 struct ConnectionData{ //... }; QObjectPrivate(int version = QObjectPrivateVersion); virtual ~QObjectPrivate(); public: ExtraData *extraData; QAtomicPointer threadData; using ConnectionDataPointer = QExplicitlySharedDataPointer; QAtomicPointer connections; union { QObject *currentChildBeingDeleted; QAbstractDeclarativeData *declarativeData; }; QAtomicPointer sharedRefcount; } Q_DECLARE_PUBLIC(QObject)定义: //qglobal.h #define Q_DECLARE_PUBLIC(Class) \ inline Class* q_func() { return static_cast(q_ptr); } \ inline const Class* q_func() const { return static_cast(q_ptr); } \ friend class Class; 翻译过后: inline QObject* q_func() { return static_cast(q_ptr); } inline const QObject* q_func() const { return static_cast(q_ptr); } \ friend class QObject; 这个宏实际上定义了2个签名不一样的函数q_func(),返回q_ptr指针,声明了QObject是友元类。 QObjectPrivate的构造器定义如下: //qobject.cpp QObjectPrivate::QObjectPrivate(int version) : threadData(nullptr), currentChildBeingDeleted(nullptr) { checkForIncompatibleLibraryVersion(version); // QObjectData initialization q_ptr = nullptr; parent = nullptr; // no parent yet. It is set by setParent() isWidget = false; // assume not a widget object blockSig = false; // not blocking signals wasDeleted = false; // double-delete catcher isDeletingChildren = false; // set by deleteChildren() sendChildEvents = true; // if we should send ChildAdded and ChildRemoved events to parent receiveChildEvents = true; postedEvents = 0; extraData = nullptr; metaObject = nullptr; isWindow = false; deleteLaterCalled = false; } 基本上是对继承下来的变量和自身变量进行初始化。
五、QObject()
当实例化一个继承自QObject的对象时,首先会调用QObject的构造器,构造器开始构造对象模型的世界,我们且看QObject构造函数QObject()的定义: //qobject.cpp QObject::QObject(QObject *parent) : QObject(*new QObjectPrivate, parent) { } //qobject.cpp QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd) { Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself"); Q_D(QObject); d_ptr->q_ptr = this; auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current(); threadData->ref(); d->threadData.storeRelaxed( threadData); if (parent) { QT_TRY { if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData)) parent = nullptr; if (d->isWidget) { if (parent) { d->parent = parent; d->parent->d_func()->children.append( this); } // no events sent here, this is done at the end of the QWidget constructor } else { setParent(parent); } } QT_CATCH(...) { threadData->deref(); QT_RETHROW; } } #if QT_VERSION q_ptr = this; 将QObjectPrivate->q_ptr设置为自身。 //qobject.cpp auto threadData = (parent && !parent->thread()) ? parent->d_func()->threadData.loadRelaxed() : QThreadData::current(); threadData->ref(); d->threadData.storeRelaxed( threadData); 检查 parent 是否非空且它所属的线程是否为空,如果都不空的话,获取parent的线程数据;否则获取当前的线程数据。将线程数据存储到对象内部的数据结构中。 //qobject.cpp if (!check_parent_thread(parent, parent ? parent->d_func()->threadData.loadRelaxed() : nullptr, threadData)) parent = nullptr; 检查parent和当前对象是否在相同的线程中,如果不在相同线程中,将 parent 设置为 nullptr。 //qobject.cpp if (d->isWidget) { if (parent) { d->parent = parent; d->parent->d_func()->children.append(this); } }else{ //... } 如果对象是一个QWidget,parent不空,则建立起对象和parent的联系,对象的父对象就是parent,parent的children添加该对象。 //qobject.cpp if (d->isWidget) { //... } else { setParent(parent); } 如果对象不是QWidget,通过setParent(parent)设置父对象。 setParent()的定义: //qobject.cpp void QObject::setParent(QObject *parent) { Q_D(QObject); Q_ASSERT(!d->isWidget); d->setParent_helper(parent); } 继续调用d->setParent_helper(parent)。 setParent_helper()的定义: void QObjectPrivate::setParent_helper(QObject *o) { Q_Q(QObject); Q_ASSERT_X(q != o, Q_FUNC_INFO, "Cannot parent a QObject to itself"); #ifdef QT_DEBUG const auto checkForParentChildLoops = qScopeGuard( [&](){ int depth = 0; auto p = parent; while (p) { if (++depth == CheckForParentChildLoopsWarnDepth) { qWarning( "QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; " "this is undefined behavior", q, q->metaObject()->className(), qPrintable(q->objectName())); } p = p->parent(); } }); #endif if (o == parent) return; if (parent) { QObjectPrivate *parentD = parent->d_func(); if (parentD->isDeletingChildren && wasDeleted && parentD->currentChildBeingDeleted == q) { // don't do anything since QObjectPrivate::deleteChildren() already // cleared our entry in parentD->children. } else { const int index = parentD->children.indexOf(q); if (index isDeletingChildren) { parentD->children[index] = 0; } else { parentD->children.removeAt(index); if (sendChildEvents && parentD->receiveChildEvents) { QChildEvent e(QEvent::ChildRemoved, q); QCoreApplication::sendEvent(parent, &e); } } } } parent = o; if (parent) { // object hierarchies are constrained to a single thread if (threadData != parent->d_func()->threadData) { qWarning( "QObject::setParent: Cannot set parent, new parent is in a different thread"); parent = nullptr; return; } parent->d_func()->children.append(q); if(sendChildEvents && parent->d_func()->receiveChildEvents) { if (!isWidget) { QChildEvent e(QEvent::ChildAdded, q); QCoreApplication::sendEvent(parent, &e); } } } if (!wasDeleted && !isDeletingChildren && declarativeData && QAbstractDeclarativeData::parentChanged) QAbstractDeclarativeData::parentChanged(declarativeData, q, o); } Q_Q(QObject)的定义: //qglobal.h #define Q_Q(Class) Class * const q = q_func() 通过q_func()获取QObjectPrivate的q_ptr,在上面我们知道q_ptr指向了QObject,所以q和q_ptr都指向QObject。 #ifdef QT_DEBUG const auto checkForParentChildLoops = qScopeGuard( [&](){ int depth = 0; auto p = parent; while (p) { if (++depth == CheckForParentChildLoopsWarnDepth) { qWarning( "QObject %p (class: '%s', object name: '%s') may have a loop in its parent-child chain; " "this is undefined behavior", q, q->metaObject()->className(), qPrintable(q->objectName())); } p = p->parent(); } }); #endif 这一段通过warning可以推断出是在检测父子关系链中是否存在循环,如果循环链深度超过阈值,则警告。 if (o == parent) return; 如果已经设置过parent且没变,直接返回。 //如果已经有parent if (parent) { //获取父对象的QObjectPrivate QObjectPrivate *parentD = parent->d_func(); //检查父对象是否正在删除其子对象,当前对象是否已经被删除,前对象是否是父对象正在删除的子对象。 //如果这些条件都成立,就跳过后续的处理,因为在删除子对象的过程中已经做了清理工作。 if (parentD->isDeletingChildren && wasDeleted && parentD->currentChildBeingDeleted == q) { // don't do anything since QObjectPrivate::deleteChildren() already // cleared our entry in parentD->children. } else { //获取当前对象在其父对象的子对象列表中的索引 const int index = parentD->children.indexOf(q); //如果索引为负数,可能表示正在从 ChildRemoved 事件中递归到 setParent(),这时不执行任何操作。 if (index isDeletingChildren) {//如果父对象正在删除其子对象,将相应的子对象指针更新为0。 parentD->children[index] = 0; } else {//否则,从父对象的子对象列表中移除当前对象 parentD->children.removeAt( index); //发送一个 ChildRemoved 事件给父对象。 if (sendChildEvents && parentD->receiveChildEvents) { QChildEvent e(QEvent::ChildRemoved, q); QCoreApplication::sendEvent(parent, &e); } } } } 上面这一段是在已有perent的情况下,断开parent和当前对象的联系,并确保在移除子对象时做了适当的清理和事件通知。实际上是为下面刷新parent做准备。 parent = o;//更新parent //parent赋值后 if (parent) { // object hierarchies are constrained to a single thread // 对象层次结构受限于单个线程 // 比较当前对象的线程数据和父对象的线程数据,如果它们不一致 if (threadData != parent->d_func()->threadData) { qWarning( "QObject::setParent: Cannot set parent, new parent is in a different thread"); //父对象置空 parent = nullptr; //直接返回 return; } //将当前对象添加到父对象的子对象列表中。 parent->d_func()->children.append( q); if(sendChildEvents && parent->d_func()->receiveChildEvents) { if (!isWidget) { //将这个事件发送给父对象 QChildEvent e(QEvent::ChildAdded, q); QCoreApplication::sendEvent(parent, &e); } } } 上面这一段是在设置对象的父对象后进行一些检查,确保父对象线程数据和该对象的一致,否则将parent设为nullptr,随后发送相应的ChildAdded事件给parent。 setParent_helper函数主要做了两件事: 1)确保旧parent安全撤离。 2)确保新parent正确设置。 简单概括一下构造函数QObject()的内容: 1)新建QObjectPrivate并赋值给d_ptr。 2)赋值d_ptr->q_ptr为对象本身。 3)初始化threadData。 4)检查当前对象和parent是否在同一线程. 5)为当前对象和parent设置关联.
六、Q_DISABLE_COPY()
//qglobal.h #define Q_DISABLE_COPY(Class) \ Class(const Class &) = delete;\ Class &operator=(const Class &) = delete; 这里删除了拷贝构造函数和拷贝赋值操作符,确保QObject不能被拷贝构造或赋值。
觉得有帮助的话,打赏一下呗。。
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。