解读Q_D和Q_Q指针
见qglog.h定义:
1
| #define Q_D(Class) Class##Private *const d = d_func()
|
1
| #define Q_Q(Class) Class * const q = q_func()
|
D指针是在主类中使用,来获取私有子类成员指针
Q指针是在私有数据类中使用,来获取主类对象指针
D指针
私有成员类总是不可见的,Qt中私有成员不仅仅是简单封装一下,将访问权限改为private,它将所有私有数据封装在私有类里(命名就是classname##private),这样一来连用户都不知道它到底封装了什么,程序中只有这个私有类成员指针,这个指针就是D指针
从QObject开始看
1 2 3 4 5 6 7 8 9
| class QObject { Q_DECLARE_PRIVATE(QObject) public: Q_INVOLABLE explicit QObject(QObject *parent = 0); protected: QObject(QObjectPrivate &dd, QObject *parent = 0); QScopedPointer<QObjectData>d_ptr; }
|
展开后
1 2 3 4 5 6 7 8 9 10 11
| class QObject { inline QObjectPrivate *d_func(){return reinterpret_cast(qGetOtrHelper(d_ptr));} inline const QObjectPrivate *d_func() const {return reinterpret_cast(qGetPtrHelp(d_ptr));} friend class QObjectPrivate; public: Q_INVOKABLE explicit QObject(QObject *parent = 0); protected: QObject(QObjectPrivate &dd, QObject *parent = 0); QScopedPointer<QObjectData> d_ptr; }
|
QObject的构造函数如下:
1 2 3 4 5 6 7 8 9 10
| QObject::QObject(QObject *parent) :d_ptr(new QObjectPrivate) { //others } QObject::QObject(QObjectPrivate &dd, QObject *parent) :d_ptr(&dd) { //others }
|
也就是QObjectData *d_ptr = new QObjectPrivate
显然QObjectPrivate继承了QObjectData;
如下
1 2 3 4 5
| QObjectData{ public: virtual ~QObjectData() = 0; //others };
|
1 2 3 4 5 6 7 8
| class Q_CORE_EXPORT QObjectPrivate:public QObjectData { Q_DECLARE_PUBLIC(QObject) public: QObjectPrivate(int version = QObjectPrivateVersion); virtual ~QObjectPrivate(); //others }
|
看看QOject的一个方法
1 2 3 4 5
| QString QObject::objectName()const { Q_D(const QObject); return d->objectName; }
|
展开后
1 2 3 4 5
| QString QObject::objectName() const { QObjectPrivate *const d = d_func(); return d->objectName; }
|
所以Qt为外卖把从d_func()获取QObjectPrivate指针的代码给封装起来了,之后就可以直接使用d->
QObject的第二个构造函数使用传入的QObjectPrivate对象,但它是protected的,也就是说,你不能在外部类中使用这个构造函数。那么这个构造函数有什么用呢?我们来看一下QWidget的代码
1 2 3 4 5 6
| class QWidget:public QObject, public QPaintDevice { Q_OBJECT; Q_DECLARE_PRIVATE(QWidget); //others }
|
QWidget是QObject的子类,然后看它的构造函数:
1 2 3 4 5 6 7 8 9 10 11
| 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; } }
|
显然了QWidgetPrivate 继承了QObjectPrivate
所以在QWidget中找不到dptr了,因为所有的dptr都已经在父类QObject中定义好了。展开QDECLAREPRIVATE宏你就能够发现,它实际上把父类的 QObjectPrivate 指针偷偷地转换成了 QWidgetPrivate 的指针。
因此有如下结论:
1、在基类中定义一个protected权限的基类私有类d_ptr指针;
2、在每个派生类中用本类私有类初始化dptr(该私有类需要继承基类私有类),并定义dfunc(),获取基类dptr,这个dfunc()是由 QDECLARE_PRIVATE展开得来的 ,并将其转换为当前私有类指针;
3、在函数中使用Q_D,这样就可以使用d了;
4、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!!!
Q指针
q指针是在私有数据类中使用的,来获取主类指针。
1 2 3 4 5 6 7
| class Q_CORE_EXPORT QObjectPrivate : public QObjectData { Q_DECLARE_PUBLIC(QObject) public: //others... };
|
展开后
1 2 3 4 5 6 7
| class Q_CORE_EXPORT QObjectPrivate : public QObjectData { 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; //others }
|
QObjectData定义如下:
1 2 3 4 5 6
| QObjectData { public: QObject *q_ptr; //others } #define Q_Q(QObject) QObject * const q = q_func()
|
三、使用的例子:
在调色板中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void QWidget::SetPalette(const QPalette &palette) { Q_D(QWidget);//得到私有成员QWidgetprivate指针d setAttribute(Qt::WA_SetPalette,palette.reolve()!=0); QPalette naturalPalette = d->naturalWidetPalette(d->inheritedPaletteResolveMask) QPalette resolvedPalette = palette.resolve(naturalPalette); d->setPalette_helper(resolvedPalette); //调用QWidgetPrivate::setPalette_helper() } void QWidgetPrivate::setPalette_helper(const QPalette &palette) { Q_Q(QWidget); if (data.pal == palette && data.pal.resolve() == palette.resolve()) return; data.pal = palette; updateSystemBackground(); propagatePaletteChange(); updateIsOpaque(); q->update(); //调用QWidget::update() updateIsOpaque(); }
|