Q_D指针在QT源码中大量的使用,其根本目的在于解决二进制兼容问题。
何为二进制兼容?
1.动态链接到库的前一个版本的程序继续与库的新版本一起运行而不需要重新编译,则库是二进制兼容的。
2.程序需要重新编译以使用新版本的库运行,但不需要任何进一步的修改,则该库是源代码兼容的。
让所有的共有类都拥有一个指针,这个指针包含所有数据的私有数据结构。
这个指针就是称为d指针的Q_D指针。
起源:
基类
/* DObject 基类 */
/*** DObject.h ***/
class DObjectPrivate;
class DObject{
public:
DObject();
~DObject();
protected:
DObjectPrivate* d_ptr_;
friend class DObjectPrivate;
};
/*** DObject.cpp ***/
#include "DObject.h"
#include "DObject_p.h"
DObject::DObject():
d_ptr_(new DObjectPrivate(this)){
}
DObject::~DObject() {
if (!!d_ptr_){
delete d_ptr_;
d_ptr_ = nullptr;
}
}
/* DObjectPrivate 基类 */
/*** DObjectPrivate.h ***/
class DObject;
class DObjectPrivate{
public:
DObjectPrivate(DObject* q_ptr);
~DObjectPrivate();
protected:
DObject* q_ptr_;
};
/*** DObjectPrivate.cpp ***/
DObjectPrivate::DObjectPrivate(DObject* q_ptr):
q_ptr_(q_ptr){
}
DObjectPrivate::~DObjectPrivate() {
}
当有派生类时:
/* 派生类 DWidget */
/*** DWidget.h ***/
#include "DObject.h"
class DWidgetPrivate;
class DWidget :
public DObject
{
public:
DWidget();
~DWidget();
protected:
friend class DWidgetPrivate;
};
/*** DWidget.cpp ***/
#include "DWidget.h"
#include "Dwidget_p.h"
DWidget::DWidget():
DObject(){
delete d_ptr_;
d_ptr_= new DWidgetPrivate(this);
}
DWidget::~DWidget() {
}
/* 派生类 DWidgetPrivate */
/*** DWidgetPrivate.h ***/
#include "DObject_p.h"
class DWidget;
class DWidgetPrivate:
public DObjectPrivate{
public:
DWidgetPrivate(DWidget* q_ptr);
~DWidgetPrivate();
protected:
friend class DWidget;
};
/*** DWidgetPrivate.cpp ***/
#include "Dwidget_p.h"
#include "DWidget.h"
DWidgetPrivate::DWidgetPrivate(DWidget* q_ptr):
DObjectPrivate(q_ptr){
delete q_ptr_;
q_ptr_ = q_ptr;
}
DWidgetPrivate::~DWidgetPrivate() {
}
这里会存在两个问题
1、DObject 与 DWidget 中的 d_ptr存在多次初始化问题
2、派生类的私有指针均为基类指针,需要强转为子类指针使用
进一步优化:
/** DObject 基类 **/
/** DObject.h **/
#define D_D(Class) Class##Private* d_fun()
#define D_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func(){return reinterpret_cast<Class##Private*> (d_ptr_);} \
inline const Class##Private* d_func() const { return reinterpret_cast<Class##Private*> (d_ptr_); } \
friend class Class##Private;
class DObjectPrivate;
class DObject{
public:
DObject();
~DObject();
protected:
DObject(DObjectPrivate* d_ptr);
protected:
DObjectPrivate* d_ptr_;
D_DECLARE_PRIVATE(DObject)
};
/** DObject.cpp **/
#include "DObject.h"
#include "DObject_p.h"
DObject::DObject():
DObject(new DObjectPrivate(this)){
}
DObject::~DObject() {
if (!!d_ptr_)
delete d_ptr_;
}
DObject::DObject(DObjectPrivate* d_ptr):
d_ptr_(d_ptr){
}
/** DObjectPrivate 基类 **/
/** DObjectPrivate.h **/
#define D_Q(Class) Class* q_fun()
#define D_DECLARE_PUBLIC(Class) \
inline Class* q_func(){return reinterpret_cast<Class*> (q_ptr_);} \
inline const Class* d_func() const { return reinterpret_cast<Class*> (q_ptr_); } \
friend class Class;
class DObject;
class DObjectPrivate{
public:
DObjectPrivate(DObject* q);
~DObjectPrivate();
protected:
DObject* q_ptr_;
D_DECLARE_PUBLIC(DObject)
};
/** DObjectPrivate.cpp **/
#include "DObject_p.h"
#include "DObject.h"
DObjectPrivate::DObjectPrivate(DObject* q) :
q_ptr_(q){
}
DObjectPrivate::~DObjectPrivate(){
}
参考资料:
https://wiki.qt.io/D-Pointer/zh
未完待续