QT(5)—— Q_D 与 Q_Q QObject与 QObjectPrivate

核心就是

QObject::QObject(QObjectPrivate &dd, QObject *parent)
    : d_ptr(&dd)
{
    d_ptr->q_ptr = this;   //互指
}
template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }

#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); } \
    inline const Class##Private* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); } \
    friend class Class##Private;

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() { return reinterpret_cast(Dptr); } \
    inline const Class##Private* d_func() const { return reinterpret_cast(Dptr); } \
    friend class Class##Private;

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

#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

  1. private 是指类的私有类Class##Private ,这个是使得类成为QT的类的实现
  2. q_func可以从q_ptr指针强制获得类的指针
  3. d_func可以从d_ptr指针强制获得类额私有类的指针
  4. q_func和d_func都有两个同名函数属于重载 ,const
  5. public 指类本身

涉及到类中的两个指针d_ptr 和q_ptr

看一下两个的定义

QObjectData *d_ptr 的定义

class Q_CORE_EXPORT QObject
{
	Q_INVOKABLE explicit QObject(QObject *parent=0);
protected:
    QObject(QObjectPrivate &dd, QObject *parent = 0);
    
    QScopedPointer<QObjectData> d_ptr;

}

QObjectData

中QObject *q_ptr 的定义

class Q_CORE_EXPORT QObjectData {
public:
    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 unused : 25;
    int postedEvents;
    QDynamicMetaObjectData *metaObject;
    QMetaObject *dynamicMetaObject() const;
};

d_ptr的初始化

Q_INVOKABLE explicit QObject(QObject *parent=0);

QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();   
}
QObject::QObject(QObjectPrivate &dd, QObject *parent)
    : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();

看一下QObjectPrivate的类型定义

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

#define Q_Q(Class) Class * const q = q_func()

class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
}

继承自QObjectData,同时通过宏扩展出一个函数q_func ,再通过Q_Q 扩展出一个类类型的指针变量q,以供获取到该私有数据类对应的类型的对象指针。

用QObjectPrivate进行赋值,QObjectPrivate是一个继承QObjectData的类型,通用的定义形式是classNamePrivate,表明是一个继承QObject的类中的私有数据,在整个继承体系中,所有类的私有数据的初始化赋值都到达了Qobject 中定义的QScopedPointer d_ptr,由其进行保存。

QT中私有数据类型的定义一般在XXX_P.h中定义,如qcoreapplication_p.h;但是实现却是和类型一起在同一个.c文件中,例如qcoreapplication.cpp。

然后通过Q_D进行类型的强制转换变为子类所持有的私有数据类型,因为QObjectData也是被各个私有数据类型进行继承和扩展的。

Q_Q的作用就是,将QObejctData中存储的QObject *q_ptr,转换成子类的类型,参数是子类的类型名,经过宏 成为类型,强制转换类型。

d_ptr和q_ptr的就是一对相互持有彼此指针的数据,从q_ptr指向的类型的可以获取到d_ptr的私有数据,通过d_ptr的私有数据类型可以获取到包含d_ptr的类型的类对象指针。

q_ptr的初始化;

QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
}

例子 ,QWidget

class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QWidget)
    
    explicit QWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
}

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
    : QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
    QT_TRY {
        d_func()->init(parent, f);
    } QT_CATCH(...) {
        QWidgetExceptionCleaner::cleanup(this, d_func());
        QT_RETHROW;
    }
}

QObject(*new QWidgetPrivate, 0) 使得第一个参数值被赋值到d_ptr,同时QObject 的构造函数中,将d_ptr的中保有的q_ptr赋值为this,即当前类型实例对象的指针。

也可以直接通过传入私有数据类型的引用进行构造,如下。

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)
    : QObject(dd, 0), QPaintDevice()
{
    Q_D(QWidget);
    QT_TRY {
        d->init(parent, f);
    } QT_CATCH(...) {
        QWidgetExceptionCleaner::cleanup(this, d_func());
        QT_RETHROW;
    }
}

你可能感兴趣的:(QT)