qt源码阅读准备

qt源码阅读准备

阅读qt源码前先了解以下知识,对阅读qt源码有极大的好处。

D-pointer介绍

D-pointer介绍

d-pointer它可以把一个类库的实施细节对使用的用户隐藏, 而且对实施的更改不会打破二进制兼容。其基本贯穿qt所有类。

Qt类的的结构

我们以QObject举例:

QObject对象叫行为类,QObjectPrivate叫数据类。

QT中大多数类的组织结构:

行为类中包含一个私有的指向数据类的指针d_ptr(就是所谓的d-pointer),

数据类中包含一个指向行为类指针q_ptr,

并且数据类对外不可见一般声明在行为类的cpp文件中。

我将QObject结构简化如下:

复制代码
QObject.h文件:
class QObjectPrivate;//因为数据类对外应该不可见,所以这里仅声明
class QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QObject)
public:
    QObject(QObject *parent=nullptr);
protected:
    QObject(QObjectPrivate &dd, QObject *parent = nullptr);
protected:
    //QScopedPointer定义智能指针
    QScopedPointer<QObjectData> d_ptr;//这就是传说中的d-pointer,
};

QObject.cpp文件:
//数据类声明在行为类的cpp文件中或单独声明在一个文件中时,仅在行为类的cpp中引用其头文件

class QObjectData {
public:
    QObject *q_ptr;//包含一个行为类成员q_ptr  
};

class QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
public:
    QObjectPrivate(int version = QObjectPrivateVersion);
} 

行为类和数据类关联实现如下:

复制代码
//数据对象初始化q_ptr为空
QObjectPrivate::QObjectPrivate(int version)
{
    q_ptr = nullptr;  
}

//public构造函数调用protected构造函数时会new一个数据类对象
QObject::QObject(QObject *parent) : QObject(*new QObjectPrivate, parent)
{
}

//将数据类对象传给d_ptr
QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;//将数据类的q_ptr指向行为类对象,即自己
}
//构造完成后行为类和数据类都相互保存对方的指针
//后面在行为类函数中就可以通过Q_D获取数据类对象
//在数据类函数中就可以通过Q_Q获取行为类对象

Q_DECLARE_PRIVATE

此宏定义在行为类 中,定义了获取数据对象d_ptr的函数d_func

主要是为了后面的宏Q_D使用。

简化其定义如下:

复制代码
宏定义中的##表示连接字符串
#define Q_DECLARE_PRIVATE(Class) \
    Class##Private* d_func() \
    {
         return d_ptr; \
    } \
     const Class##Private* d_func() const \
    {\ 
        return d_ptr; \
    } \
    friend class Class##Private;

Q_DECLARE_PRIVATE(QObject)转换后如下:
    QObjectPrivate* d_func() 
    {
         return d_ptr; 
    } 
     const QObjectPrivate* d_func() const 
    {
        return d_ptr; 
    }
    friend class QObjectPrivate;

Q_DECLARE_PUBLIC

此宏定义在数据类 中,定义了获取行为对象的函数q_func

主要是为了后面的宏Q_Q使用。

简化其定义如下:

复制代码
#define Q_DECLARE_PUBLIC(Class)  \
    Class* q_func() \
    { \
         return q_ptr; \ 
         } \
    const Class* q_func() const\
    { \
         return q_ptr; \
    } \
    friend class Class;

Q_DECLARE_PUBLIC(QObject)转换后如下:
    QObject* q_func()
    { 
        return q_ptr; 
    } 
    const QObject* q_func() const
    {
        return q_ptr;
    }
    friend class QObject;

Q_D

此宏在行为类 函数中使用,用来定义一个指向数据对象d_ptr的指针d,

以供函数后面直接使用d

其定义如下:

复制代码
#define Q_D(Class) Class##Private * const d = d_func()

Q_D(QObject);转换后:QObjectPrivate * const d = d_func();
由Q_DECLARE_PRIVATE(QObject)可知d_func返回的是d_ptr

void QObject::setParent(QObject *parent)
{
    Q_D(QObject);//转换后为QObjectPrivate * const d = d_ptr;
    d->setParent_helper(parent);//可以直接使用d指针操作数据类对象
}

Q_Q

此宏在数据类 函数中使用,用来定义一个指向行为类对象q_ptr的指针q,

以供函数后面直接使用q

其定义如下:

复制代码
#define Q_Q(Class) Class * const q = q_func()

Q_Q(QObject);转换后QObject * const q = q_func();
由Q_DECLARE_PUBLIC(QObject)可知q_func返回的是q_ptr

void QObjectPrivate::moveToThread_helper()
{
    Q_Q(QObject);//QObject * const q = q_ptr;
    QEvent e(QEvent::ThreadChange);
    QCoreApplication::sendEvent(q, &e);
    ...
}

Q_OBJECT

此宏用于定义元对象,需要使用QObject的信号关联必须定义此宏,并且需要在类定义最前面定义此宏

复制代码
简化定义如下:
#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: \
    static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    struct QPrivateSignal {}; \

QMetaObject元对象保存了类的基本信息是对类的描述,记录了类名称,槽、信号、函数数量偏移等。QMetaObject对象的初始化是通过qt元对象编译器moc编译后自动生成的。

继承QObject的类结构

继承QObject的类都有自己的特有数据类,其继承了QObject数据对象类。

在构造过程中是将自己的数据对象类,最终传给父亲类QObject的d_ptr,

也保证了每个对象仅有一个数据对象类指针,而不是每层级都有自己的d_ptr

复制代码
1、
class QFtpPrivate : public QObjectPrivate
{};
//直接调用QObject的protected构造函数传入QObjectPrivate指针
QFtp::QFtp(QObject *parent) : QObject(*new QFtpPrivate, parent)
{
}

2、
class QActionGroupPrivate : public QObjectPrivate
{};
QActionGroup::QActionGroup(QObject* parent) : QObject(*new QActionGroupPrivate, parent)
{
}

3、
class  QWidgetPrivate : public QObjectPrivate
{};

class  QWidget : public QObject, public QPaintDevice
{
public:
 explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags);
protected:
    QWidget(QWidgetPrivate &d, QWidget* parent, Qt::WindowFlags f);
};

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()
{
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()
{
}

get(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()

{

}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()

{

}

复制代码
相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
桥田智能16 天前
桥田智能 QT-650S:面向白车身焊装的 800kg 重载快换解决方案
开发语言·qt·系统架构
森G16 天前
75、服务器源码解析---------云视频服务项目
linux·服务器·网络·c++·qt