前面我們已經看到了怎樣使用標準的 c++ **以及 qt 提供的 api 來達到資訊隱藏這一目標。下面我們來看一下 qt 是如何實現的。
還是以 qobject 的源**作為例子。先開啟 qobject.h,找到 qobjectdata 這個類的宣告。具體**如下所示:
qobjectdata ;
然後在下面就可以找到 qobject 的宣告:
class qobject
注意,這裡我們只是列出了我們所需要的**,並且我的 qt 版本是 2010.03。這部分**可能會隨著不同的 qt 版本所有不同。
首先先了解一下 qt 的設計思路。既然每個類都應該把自己的資料放在乙個 private 類中,那麼,為什麼不把這個操作放在幾乎所有類的父類 qobject 中呢?所以,qt 實際上是用了這樣乙個思路,實現了我們前面介紹的資料隱藏機制。
首先回憶一下,我們前面說的 d-pointer 需要有乙個 private 或者 protected 的指向自己資料類的指標。在 qobject 中,
qscopedpointerd_ptr;
就扮演了這麼乙個角色。或許,你可以把它理解成
qobjectdata *d_ptr;
這不就和我們前面說的 d-pointer 技術差不多了?qscopedpointer 是 qt 提供的乙個輔助類,這個類儲存有乙個指標,它的行為類似於一種智慧型指標:它能夠保證在這個作用域結束後,裡面的所有指標都能夠被自動 delete 掉。也就是說,它其實就是乙個比普通指標更多功能的指標。而這個指標被宣告成 protected 的,也就是只有它本身以及其子類才能夠訪問到它。這就提供了讓子類不必須宣告這個 d-pointer 的可能。
那麼,前面我們說,qobjectdata 這種資料類不應該放在公開的標頭檔案中,可 qt 怎麼把它放進來了呢?這樣做的用途是,qobject 的子類的資料類都可能繼承自這個 qobjectdata。這個類有乙個純虛的析構函式。沒有實現**,保證了這個類不能被初始化;虛的析構函式,保證了其子類都能夠被正確的析構。
回到我們前面說明的 q_declare_private 這個巨集:
#define q_declare_private(class) \
inline class##private* d_func() \
inline const class##private* d_func() const \
friend class class##private;
我們把**中的 q_declare_private(qobject) 展開看看是什麼東西:
inline qobjectprivate* d_func()
inline const qobjectprivate* d_func() const
friend class qobjectprivate;
清楚是清楚,只是這個 qobjectprivate 是**來的?既然是 private,那麼它肯定不會在公開的標頭檔案中。於是我們立刻想到到 qobject.cpp 或者是 qobject_p.h 中尋找。終於,我們在 qobject_p.h 中找到了這個類的宣告:
class q_core_export qobjectprivate : public qobjectdata
這個類是繼承 qobjectdata 的!想想也是,因為我們說過,qobjectdata 是不能被例項化的,如果要使用,必須建立它的乙個子類。顯然,qobjectprivate 就扮演了這麼乙個角色了。不僅如此,我們還在這裡看到了熟悉的 q_declare_public 巨集。好在我們已經知道它的含義了。
在 qobject.cpp 中,我們看一下 qobject 的建構函式:
qobject::qobject(qobject *parent)
: d_ptr(new qobjectprivate)
qobject::qobject(qobjectprivate &dd, qobject *parent)
: d_ptr(&dd)
第乙個建構函式就是我們經常見到的那個。它使用自己建立的 qobjectprivate 指針對 d_ptr 初始化。第二個建構函式使用傳入的 qobjectprivate 物件,但它是 protected 的,也就是說,你不能在外部類中使用這個建構函式。那麼這個建構函式有什麼用呢?我們來看一下 qwidget 的**:
class qwidget : public qobject, public qpaintdevice
qwidget 是 qobject 的子類,然後看它的建構函式:
qwidget::qwidget(qwidget *parent, qt::windowflags f)
: qobject(*new qwidgetprivate, 0), qpaintdevice()
qt_catch(...)
}
它呼叫了那個qobject 的 protected 建構函式,並且傳入乙個 qwidgetprivate !這個 qwidgetprivate 顯然繼承了 qobjectprivate。於是我們已經明白,為什麼 qwidget 中找不到 d_ptr 了,因為所有的 d_ptr 都已經在父類 qobject 中定義好了!嘗試展開一下 q_declare_private 巨集,你就能夠發現,它實際上把父類的 qobjectprivate 指標偷偷地轉換成了 qwidgetprivate 的指標。這個就是前面說的 qt 的設計思路。 Qt核心剖析 資訊隱藏 3
原始出處 作者資訊和本宣告。否則將追究法律責任。前面我們已經看到了怎樣使用標準的 c 以及 qt 提供的 api 來達到資訊隱藏這一目標。下面我們來看一下 qt 是如何實現的。還是以 qobject 的源 作為例子。先開啟 qobject.h,找到 qobjectdata 這個類的宣告。具體 如下所...
Qt核心剖析 資訊隱藏
如果你閱讀了 qt 的源 你會看到一堆奇奇怪怪的巨集,例如 q d,q q。我們的qt原始碼之旅就從理解這些巨集說起。下面先看乙個c 的例子。class person person string name void setname string name int age void setage in...
Qt核心剖析 資訊隱藏 1
如果你閱讀了 qt 的源 你會看到一堆奇奇怪怪的巨集,例如 q d,q q。我們的qt原始碼之旅就從理解這些巨集說起。下面先看乙個c 的例子。class person person string name void setname string name int age void setage in...