此文章可以参考:
Pimpl技术的基本应用
PImpl机制以及Qt的D-Pointer实现
Qt的d_ptr本质上使用了pimp技术
D指针
保持一个库中的所有公有类的大小恒定的问题可以通过单独的私有指针给予解决。这个指针指向一个包含所有数据的私有数据结构体。这个结构体的大小可以随意改变而不会产生副作用,应用程序只使用相关的公有类,所使用的对象大小永远不会改变,它就是该指针的大小。这个指针就被称作D指针。
/* widget.h */
// 私有数据结构体声明。 其定义会在 widget.cpp 或是
// widget_p.h,总之不能在此头文件
class WidgetPrivate;
class Widget {
...
Rect geometry()const;
...
private:
// d指针永远不能在此头文件中被引用
// 由于WidgetPrivate没有在此头文件中被定义,
// 任何访问都会导致编译错误。
WidgetPrivate *d_ptr;
};
/* widget_p.h */(_p 指示private)
struct WidgetPrivate {
Rect geometry;
String stylesheet;
};
/* widget.cpp */
#include "widget_p.h"
Widget::Widget()
: d_ptr(new WidgetPrivate)// 初始化 private 数据 {
}
Rect Widget::geoemtry()const{
// 本类的d指针只能被在自己的库内被访问
return d_ptr->geometry;
}
/* label.h */
class LabelPrivate;
class Label :publicWidget {
...
String text();
private:
// 自己类对应自己的d指针
LabelPrivate *d_ptr;
};
/* label.cpp */
// 这里将私有结构体在cpp中定义
struct LabelPrivate {
String text;
};
Label::Label()
: d_ptr(new LabelPrivate) {
}
String Label::text() {
return d_ptr->text;
}
有了上面的结构,CuteApp就不会与d指针直接打交道。因为d指针只能在WidgetLib中被访问,在每一次对Widget修改之后都要对其重新编译,私有的结构体可以随意更改,而不需要重新编译整个工程项目。
D指针的其他好处
除了以上优点,d指针还有如下优势:
1.隐藏实现细节——我们可以不提供widget.cpp文件而只提供WidgetLib和相应的头文件和二进制文件。
2.头文件中没有任何实现细节,可以作为API使用。
3.由于原本在头文件的实现部分转移到了源文件,所以编译速度有所提高。
其实以上的点都很细微,自己跟过源代码的人都会了解,qt是隐藏了d指针的管理和核心源的实现。像是在_p.h中部分函数的声明,qt也宣布在以后版本中将会删除。( This file is not part of the Qt API. It exists purely as an implementation detail. This header file may change from version to version without notice, or even be removed.)
Q指针
到目前为止,我们已经熟悉了指向私有结构体的d指针。而在实际中,往往它将包含私有方法(helper函数)。例如,LabelPrivate可能会有getLinkTargetFromPoint()(helper函数)以当按下鼠标时去找到相应的链接目标。在很多场合,这些helper函数需要访问公有类,例如访问一些属于Label类或是其基类Widget的函数。
比方说,一个帮助函数setTextAndUpdateWidget()可能会调用Widget::update()函数去重新绘制Widget。因此,我们同样需要WidgetPrivate存储一个指向公有类的q指针。
/* widget.h */
class WidgetPrivate;
class Widget {
...
Rect geometry()const;
...
private:
WidgetPrivate *d_ptr;


3495

被折叠的 条评论
为什么被折叠?



