类结构

先分析qt gui程序最常用的两个大类QApplication和QWidget的继承关系,如下:

在分析QApplication和QWidget的构造过程,如下:

结合继承关系和构造过程分析类结构:

① 以QObject为基类,QObject ◁﹣QCoreApplication ◁﹣QGuiApplication ◁﹣QApplication,QApplication到顶,QApplication  是派生类的最顶端,没有内部构造函数,其他都有一个内部构造和一个外部构造,外部构造直接通过外部参数来构造,内部构造需带一个QXXXPrivate类指针参数,这是我们通过继承关系和构造过程来分析出来的;

② QObjectData ◁﹣QObjectPrivate ◁﹣QCoreApplicationPrivate ◁﹣QGuiApplicationPrivate ◁﹣QApplicationPrivate,这是内部的一条非常重要的继承关系,当构造QXXXApplication时,都会先new一个QXXXApplicationPrivate对象,并通过它继承的基类内部构造函数先构造基类;

所有第一个结论如下:

     继承于QObject类,QXXX必然聚合了一个继承于QObjectData的QXXXPrivate类,

③ 以QObject为基类QObject ◁﹣QWidget .....,从继承关系上分析类似于QXXXAplication,不同之处在于这条继承链没有顶端,用户可以自定义然后继续继承;

④ 从构造函数来分析,以QWidget为基类的QXXX类构造函数都多了一个QXXX*参数,其目的就是为了构成一个树形结构对象集合,根节点该参数为null,除了根节点,每个节点都有父QObject ,也可以有子QObject;区别于QXXXAplication是因为每个进程只允许有一个QXXXAplication对象;

⑤ 树形结构依赖QObjectData中定义的QObject *parent; QObjectList children;,如下:

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


 ⑥ 最终结论,如下:

继承于QObject类的QXXX的类必然聚合了一个继承于QObjectData的QXXXPrivate类,QObject中d_ptr指向QXXXPrivate,QObjectData中q_ptr指向QXXX,parent存放父节点,children存放子节点;
d指针和q指针

原始d_ptr指针和q_ptr指针的定义,如下图:

PS:d_ptr可以看成指向QObjectData类的智能指针

实际使用d指针和p指针的定义,如下图:

以QWidget为例:

QScopedPointer<QObjectData> d_ptr; // d_ptr指向QWidgetPrivate基类智能指针

QObject *q_ptr;                                      // q_ptr指向QWidget指针

d_ptr = new QWidgetPrivate                 // 本质是这样的,但实际有附录源码参考

q_ptr = new QWidget                            // 本质是这样的,但实际有附录源码参考

QWidgetPrivate* d;                               // QWidget类方法中的局部变量

QWidget* q;                                          // QWidgetPrivate类方法中的局部变量


d_ptr到d的转换和q_ptr到q的转换,如下图:

 源代码中d_ptr与q_ptr赋值过程和d与q使用过程,如下:

// QObject公开构造方法 qobject.cpp 814行
QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
   
    ...
}
// QObject保护构造方法 qobject.cpp 839行
QObject::QObject(QObjectPrivate &dd, QObject *parent)
    : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    
    ...
}
// QWidget公开构造方法 qwidget.cpp 1020行
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;
    }
}
// QWidget保护构造方法 qwidget.cpp 1034行
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;
    }
}

另外几个相关宏定义和模板函数,如下:

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<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;
    
#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;    
    
#define Q_D(Class) Class##Private * const d = d_func()

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

编译器

moc(Meta-Object Compiler)

uic(User Interface Compiler)

rcc(Resource Compiler)