Qt核心機制:QObject Model(QObejct)

Qt助手:Object

Qt源碼解析:

// Src/qtbase/src/corelib/kernel/qobject.h
class Q_CORE_EXPORT QObject
{
    Q_OBJECT                                         // 提供元對象指針
    Q_DECLARE_PRIVATE(QObject)                       // 提供訪問QObjectPrivate對象的接口

public:
    Q_INVOKABLE explicit QObject(QObject *parent=0);
    virtual ~QObject();

protected:
    QObject(QObjectPrivate &dd, QObject *parent = 0);// 受保護構造函數,對外部屏蔽QObjectPrivate

protected:
    QScopedPointer<QObjectData> d_ptr;               // QObjectPrivate指針

private:
    Q_DISABLE_COPY(QObject)                          // 私有化拷貝構造和賦值函數
    Q_PRIVATE_SLOT(d_func(), void _q_reregisterTimers(void *))
};

疑問1:QObjectPrivate的作用?

疑問2:拷貝構造和賦值函數的私有化的作用?

// Src/qtbase/src/corelib/kernel/qobject_p.h
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)                         // 提供訪問QObject對象的接口

public:
    QObjectPrivate(int version = QObjectPrivateVersion);
    virtual ~QObjectPrivate();
    
public:
    ExtraData *extraData;                             // extra data set by the user
    QThreadData *threadData;                          // id of the thread that owns the object
};
// Src/qtbase/src/corelib/kernel/qobject.h
class Q_CORE_EXPORT QObjectData {
public:
    virtual ~QObjectData() = 0;                // 純虛析構,所有private數據類必須從此類派生
    QObject *q_ptr;                            // 數據類對應的接口類指針
    QObject *parent;                           // 父
    QObjectList children;                      // 所有子
    uint isWidget : 1;                         // 快速判斷是否從QWidget繼承,比metaObjectName、強制轉換快
    uint blockSig : 1;                         // 是否暫停信號、槽
    uint wasDeleted : 1;                       // 
    uint isDeletingChildren : 1;               //
    uint sendChildEvents : 1;                  //
    uint receiveChildEvents : 1;               //
    uint isWindow : 1;                         // for QWindow
    uint unused : 25;                          // 預留
    int postedEvents;                          // 
    QDynamicMetaObjectData *metaObject;        //  
    QMetaObject *dynamicMetaObject() const;    //
};
// include/QtCore/qglobal.h
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \
    friend class Class##Private;

// Q_DECLARE_PRIVATE(QObject)展開
inline QObjectPrivate* d_func() { return reinterpret_cast<QObjectPrivate *>(qGetPtrHelper(d_ptr)); } \
inline const QObjectPrivate* d_func() const { return reinterpret_cast<const QObjectPrivate *>(qGetPtrHelper(d_ptr)); } \
friend class QObjectPrivate;


#define Q_DECLARE_PUBLIC(Class) \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

// Q_DECLARE_PUBLIC(QObject)展開
inline QObject* q_func() { return static_cast<QObject *>(q_ptr); } \
inline const QObject* q_func() const { return static_cast<const QObject *>(q_ptr); } \
friend class QObject;

疑問3:QObject、QObjectPrivate如何關聯?

疑問4:從QObject派生的類與其XXXPrivate類如何關聯?

分析1:

  • QObject提供接口,QObjectPrivate存儲數據
  • QObject對外暴露,QObjectPrivate對外隱藏
  • QObjectPrivate變化不影響QObject,減少依賴,提高編譯速度

分析3:

  • 通過構造函數完成QObject、QObjectPrivate的關聯
// Src/qtbase/src/corelib/kernel/qobject.cpp
QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    ...
}

QObject::QObject(QObjectPrivate &dd, QObject *parent)
    : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    ...
}

分析4:

  • 以QWidget爲例,通過受保護的構造函數完成關聯
// Src/qtbase/src/widgets/kernel/qwidget.cpp
QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
    : QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
    d_func()->init(parent, f);
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)
    : QObject(dd, 0), QPaintDevice()
{
    Q_D(QWidget);
    d->init(parent, f);
}

分析3:

  • 每個QObject都有一個ObjectName
  • 每個QObject內部會信號、槽鏈接
  • 每個QObject會有自定義的property
  • 對於上述內容,拷貝構造、複製函數都不好處理,所以把這兩個函數私有化
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章