1.二进制兼容性
所谓二进制兼容就是在做版本升级(也可能是Bug fix)库文件的时候,不必要做重新编译使用这个库的可执行文件或使用这个库的其他库文件,同时能保证程序功能不被破坏。
比如修改一个类的成员变量,新增
对象的内存就会增大,根据对象的指针加便宜的方式就不能访问到正确的数据
2.D指针
保持一个库中的所有公有类的大小恒定的问题可以通过单独的私有指针给予解决。这个指针指向一个包含所有数据的私有数据结构体。这个结构体的大小可以随意改变而不会产生副作用,应用程序只使用相关的公有类,所使用的对象大小永远不会改变,它就是该指针的大小。这个指针就被称作D指针。
4.Q指针
到目前为止,我们已经熟悉了指向私有结构体的d指针。而在实际中,往往它将包含私有方法(helper函数)。例如,LabelPrivate可能会有getLinkTargetFromPoint()(helper函数)以当按下鼠标时去找到相应的链接目标。在很多场合,这些helper函数需要访问公有类,例如访问一些属于Label类或是其基类Widget的函数。
template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
#define QT_WARNING_PUSH __pragma(warning(push))
#define QT_WARNING_DISABLE_GCC(text)
#define QT_WARNING_POP __pragma(warning(pop))
#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;
#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;
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
class MyClass;
class MyClassPrivate
{
public:
Q_DECLARE_PUBLIC(MyClass);
MyClassPrivate(MyClass* pParent): q_ptr(pParent){ }
void setId(int nId) { m_nId = nId; }
void doRun()
{
//声明MyClass 不能调用 run
//q 作为局部变量
//Q_Q(MyClass);
//q->run();
}
private:
MyClass* const q_ptr;
//成员变量保存在Private类型不对外公开,且可以随意增加
int m_nId;
};
class MyClass
{
public:
MyClass() : d_ptr(new MyClassPrivate(this)){ }
~MyClass() { delete d_ptr; }
void setId(int nId) { d->setId(nId); }
virtual void run() {}
private:
MyClassPrivate* const d_ptr;
Q_DECLARE_PRIVATE(MyClass);
Q_D(MyClass);
};
int main()
{
MyClass myClass;
myClass.setId(6);
return 0;
}