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;
}