在查看qt的源码时候,发现Qt会将数据单独抽象成一个Class##Private 类,所有的成员变量的都是由这个类来保存的。
例如:QThread 类,可以看到从表面上没有看到任何成员变量,那我们就来看看qt是如何巧妙的来完成这个内容的。
class Q_CORE_EXPORT QThread : public QObject
{
Q_OBJECT
public:
static Qt::HANDLE currentThreadId() Q_DECL_NOTHROW Q_DECL_PURE_FUNCTION;
static QThread *currentThread();
explicit QThread(QObject *parent = nullptr);
~QThread();
....
protected:
virtual void run();
int exec();
private:
Q_DECLARE_PRIVATE(QThread)
friend class QCoreApplication;
friend class QThreadData;
};
qt 类的成员变量
Q_DECLARE_PRIVATE(QThread)
template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(const Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); }
// The body must be a statement:
#define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP
// 宏
#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() \
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
inline const Class##Private* d_func() const \
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \
friend class Class##Private;
2个内联函数,返回时Class##Private* 的指针。
inline Class##Private* d_func()
inline const Class##Private* d_func() const
为了让Class##Private 可以访问私有函数,设置为友元类。
friend class Class##Private;
Pirvate的类保存在哪?
qGetPtrHelper的作用是通过模板方式将指针或者对象,转换成指针。
其中d_ptr 是QObject的成员变量的指针,是在类构造函数赋值的,也就Class##Private 类。所以我们也就知道在创建QThread类的时候,QThread会创建一个包含数据成员的类QThreadPrivate
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_D(QObject);
d_ptr->q_ptr = this;
}
QThread::QThread(QObject *parent)
: QObject(*(new QThreadPrivate), parent)
{
Q_D(QThread);
d->data->thread = this;
}
如何访问和使用
Class 访问 ClassPrivate
通过第一节的讲解之后,我们知道了,类是通过Class##Private 类对象保存到d_ptr中的,那如何访问和使用呢,就会用到下面的宏。也就是d_func() 返回一个Class##Private * 类型的指针。
#define Q_D(Class) Class##Private * const d = d_func()
所以访问成员变量就可以直接使用d->data->thread 的方式直接访问。
QThread::QThread(QObject *parent)
: QObject(*(new QThreadPrivate), parent)
{
Q_D(QThread);
d->data->thread = this;
}
ClassPrivate 访问 Class
接下来我看一下,在QThreadPrivate中是如何访问QThread的
首先:ClassPrivate都是继承与QObjectPrivate的
第二:和Q_DECLARE_PRIVATE 相对的有Q_DECLARE_PUBLIC的宏就为了访问Class 。形式一样不做过多的介绍。
#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;
class QThreadPrivate : public QObjectPrivate
{
public:
QThreadPrivate(QThreadData *d = 0);
~QThreadPrivate();
mutable QMutex mutex;
QThreadData *data;
bool running = false;
static void setCurrentThread(QThread*) {}
static QThread *threadForId(int) { return QThread::currentThread(); }
static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
void ref() {}
void deref() {}
Q_DECLARE_PUBLIC(QThread)
};
小结
1、为什么会这样做
由于QThread类是Q_CORE_EXPORT ,是导出类,外部可以可以看到类的声明包括内部变量,但是内部的数据是不希望被外部看到的,所以将所有的数据成员变量封装成一个私有类,不暴露实现细节的目的。
2、通过宏Q_DECLARE_PRIVATE 来声明,Q_D来访问。