接上節,讓我們來看看這個 QObjectPrivate 和 QObject 是如何關聯在一起的。
//————————————————————————————————————–
// file name: qobject.cpp
QObject::QObject(QObject *parent)
: d_ptr(new QObjectPrivate)
{
// ………………………
}
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
// …………………
}
怎麼樣,是不是一目瞭然呀?
從第一個建構函式可以很清楚的看出來,QObject class 中的 d_ptr 指標將指向一個 QObjectPrivate 的對象,而QObjectPrivate這個class是從QObjectData繼承出來的。
這第二個建構函式幹什麼用的呢?從 QObject class 的定義中,我們可以看到,這第二個建構函式是被定義為 protected 類型的,這說明,這個建構函式只能被繼承的class使用,而不能使用這個建構函式來直接構造一個QObject對象,也就是說,如果寫一條下面的語句,編譯的時候是會失敗的,
new QObject(*new QObjectPrivate, NULL)
為了看的更清楚,我們以QWidget這個class為例說明。
QWidget是QT中所有UI控制項的基類,它直接從QObject繼承而來,
class QWidget : public QObject, public QPaintDevice
{
Q_OBJECT
Q_DECLARE_PRIVATE(QWidget)
// …………………
}
我們看一個這個class的建構函式的代碼:
QWidget::QWidget(QWidget *parent, Qt::WindowFlags f)
: QObject(*new QWidgetPrivate, 0), QPaintDevice()
{
d_func()->init(parent, f);
}
非常清楚,它調用了基類QObject的保護類型的建構函式,並且以 *new QWidgetPrivate 作為第一個參數傳遞進去。也就是說,基類(QObject)中的d_ptr指標將會指向一個QWidgetPrivate類型的對象。
再看QWidgetPrivate這個class的定義:
class QWidgetPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QWidget)
// …………………
}
好了,這就把所有的事情都串聯起來了。
關於QWidget建構函式中的唯一的語句 d_func()->init(parent, f) 我們注意到在class的定義中有這麼一句話: Q_DECLARE_PRIVATE(QWidget)
我們前面講過這個宏,當把這個宏展開之後,就是這樣的:
inline QWidgetPrivate* d_func() { return reinterpret_cast<QWidgetPrivate *>(d_ptr); }
inline const QWidgetPrivate* d_func() const
{ return reinterpret_cast<const QWidgetPrivate *>(d_ptr); } /
friend class QWidgetPrivate;
很清楚,它就是把QObject中定義的d_ptr指標轉換為QWidgetPrivate類型的指標。
小結:
要理解Qt Kernel的code,就必須要知道Qt中每一個Object內部的資料是如何儲存的,而Qt沒有象我們平時寫code一樣,把所有的變數直接定義在類中,所以,不搞清楚這個問題,我們就無法理解一個相應的class。其實,在Qt4.6中的類成員資料的儲存方法在本質是與Qt2.x中的是一樣的,就是在class中定義一個成員資料的指標,指向成員資料集合對象(這裡是一個QObjectData或者是其衍生類別)。初始化這個成員變數的辦法是定義一個保護類型的建構函式,然後在衍生類別的建構函式new 一個衍生類別的資料成員,並將這個新對象賦值給QObject的資料指標。在使用的時候,通過預先定義個宏裡面的一個inline函數來把資料指標在安全類型轉換,就可以使用了。
======================================================================
聲明:
《Inside Qt Series》專欄文章是(http://www.qkevin.com)原創技術文章。
本系列專欄文章可隨意轉載,但必須保留本段聲明和每一篇文章的原始地址。
作者保留著作權,未經作者同意,不得用於任何商業用途
《Inside Qt Series》專欄文章總索引: http://www.qkevin.com/qt
本文原始地址:http://www.qkevin.com/archives/63