所有QObject的派生類在官方文檔中都推薦在頭文件中放置宏Q_OBJECT,那麼該宏到底爲我們做了哪些工作?在qobjectdef.h中有下面的代碼:
- #define Q_OBJECT \
- public: \
- Q_OBJECT_CHECK \
- static const QMetaObject staticMetaObject; \
- Q_OBJECT_GETSTATICMETAOBJECT \
- virtual const QMetaObject *metaObject() const; \
- virtual void *qt_metacast(const char *); \
- QT_TR_FUNCTIONS \
- virtual int qt_metacall(QMetaObject::Call, int, void **); \
- private:
首先定義了一個Q_OBJECT_CHECK宏,這個宏在Q_OBJECT宏的上方定義:
- #define Q_OBJECT_CHECK \
- template <typename T> inline void qt_check_for_QOBJECT_macro(const T &_q_argument) const \
- { int i = qYouForgotTheQ_OBJECT_Macro(this, &_q_argument); i = i; }
Q_OBJECT_CHECK實現了一個模板函數,該函數調用了qYouForgotTheQ_OBJECT_Macro的函數,qYouForgotTheQ_OBJECT_Macro在宏Q_OBJECT_CHECK下面有定義:
- template <typename T>
- inline int qYouForgotTheQ_OBJECT_Macro(T, T) { return 0; }
- template <typename T1, typename T2>
- inline void qYouForgotTheQ_OBJECT_Macro(T1, T2) {}
從返回值情況上可以看到,調用的是有int返回值的那個模板函數。但是很不明白,爲什麼之後還要添加一句 i=i?,刨根之後,發現Q_OBJECT_CHECK宏並沒有做什麼工作。
然後Q_OBJECT又幫我們定義了一個靜態的元對象,
- static const QMetaObject staticMetaObject; \
- Q_OBJECT_GETSTATICMETAOBJECT \
Q_OBJECT_GETSTATICMETAOBJECT宏從名字上看就是爲了獲取這個元對象,確實在定義了Q_NO_DATA_RELOCATION宏的情況下,Q_OBJECT_GETSTATICMETAOBJECT宏就爲我們定義了獲取靜態元對象的方法。
- #ifdef Q_NO_DATA_RELOCATION
- #define Q_OBJECT_GETSTATICMETAOBJECT static const QMetaObject &getStaticMetaObject();
- #else
- #define Q_OBJECT_GETSTATICMETAOBJECT
- #endif
之後Q_OBJECT宏又給我們定義了連個虛函數用來獲取元對象指針和設置源對象。
- virtual const QMetaObject *metaObject() const; \
- virtual void *qt_metacast(const char *); \
而定義的 QT_TR_FUNCTIONS 則表示是否支持I18N。
- #ifndef QT_NO_TRANSLATION
- # ifndef QT_NO_TEXTCODEC
- // full set of tr functions
- // ### Qt 5: merge overloads
- # define QT_TR_FUNCTIONS \
- static inline QString tr(const char *s, const char *c = 0) \
- { return staticMetaObject.tr(s, c); } \
- static inline QString trUtf8(const char *s, const char *c = 0) \
- { return staticMetaObject.trUtf8(s, c); } \
- static inline QString tr(const char *s, const char *c, int n) \
- { return staticMetaObject.tr(s, c, n); } \
- static inline QString trUtf8(const char *s, const char *c, int n) \
- { return staticMetaObject.trUtf8(s, c, n); }
- # else
- // no QTextCodec, no utf8
- // ### Qt 5: merge overloads
- # define QT_TR_FUNCTIONS \
- static inline QString tr(const char *s, const char *c = 0) \
- { return staticMetaObject.tr(s, c); } \
- static inline QString tr(const char *s, const char *c, int n) \
- { return staticMetaObject.tr(s, c, n); }
- # endif
- #else
- // inherit the ones from QObject
- # define QT_TR_FUNCTIONS
- #endif
只要有所實現,tr的方法就通過靜態對象staticMetaObject的tr方法來實現。最後Q_OBJECT又定義了一個虛函數
- virtual int qt_metacall(QMetaObject::Call, int, void **);
看名字定義,應該是用來對元對象的調用。
合起來看所有的Q_OBJECT定義,都是爲了操作元對象,並沒有所謂的信號和槽,屬性等內容,很顯然,QObject對象能夠支持這些功能,必然是通過QMetaObject這個元對象來實現的。儘管QMetaObject對象的實現有些龐大,但這個是所有的QOBject中最核心的一個實現,因此需要仔細分析該對象的每個定義:
- struct Q_CORE_EXPORT QMetaObject
- {
- const char *className() const; // 類名
- const QMetaObject *superClass() const; // 父類的元對象
- QObject *cast(QObject *obj) const; // 強制一個對象
- #ifndef QT_NO_TRANSLATION
- // ### Qt 4: Merge overloads
- QString tr(const char *s, const char *c) const; // 翻譯函數
- QString trUtf8(const char *s, const char *c) const;
- QString tr(const char *s, const char *c, int n) const;
- QString trUtf8(const char *s, const char *c, int n) const;
- #endif // QT_NO_TRANSLATION
- int methodOffset() const; // 方法偏移量
- int enumeratorOffset() const; // 枚舉偏移量
- int propertyOffset() const; // 屬性偏移量
- int classInfoOffset() const; // 類信息數目
- int constructorCount() const; // 構造函數數目
- int methodCount() const; // 方法數目
- int enumeratorCount() const; // 枚舉數據
- int propertyCount() const; // 屬性數目
- int classInfoCount() const; // 類信息數目
- int indexOfConstructor(const char *constructor) const; // 構函函數索引
- int indexOfMethod(const char *method) const; // 方法索引
- int indexOfSignal(const char *signal) const; // 信號量索引
- int indexOfSlot(const char *slot) const; // 槽索引
- int indexOfEnumerator(const char *name) const; // 枚舉索引
- int indexOfProperty(const char *name) const; // 屬性索引
- int indexOfClassInfo(const char *name) const; // 類信息索引
- QMetaMethod constructor(int index) const; // 構造方法
- QMetaMethod method(int index) const; // 方法
- QMetaEnum enumerator(int index) const; // 枚舉
- QMetaProperty property(int index) const; // 屬性
- QMetaClassInfo classInfo(int index) const; // 類屬性信息
- QMetaProperty userProperty() const; // 用戶屬性
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
- static bool checkConnectArgs(const char *signal, const char *method);
- static QByteArray normalizedSignature(const char *method);
- static QByteArray normalizedType(const char *type);
- // internal index-based connect
- static bool connect(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index,
- int type = 0, int *types = 0);
- // internal index-based disconnect
- static bool disconnect(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index);
- static bool disconnectOne(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index);
- // internal slot-name based connect
- static void connectSlotsByName(QObject *o);
- // internal index-based signal activation
- static void activate(QObject *sender, int signal_index, void **argv); //obsolete
- static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv); //obsolete
- static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
- static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv); //obsolete
- // internal guarded pointers
- static void addGuard(QObject **ptr);
- static void removeGuard(QObject **ptr);
- static void changeGuard(QObject **ptr, QObject *o);
- static bool invokeMethod(QObject *obj, const char *member,
- Qt::ConnectionType,
- QGenericReturnArgument ret,
- QGenericArgument val0 = QGenericArgument(0),
- QGenericArgument val1 = QGenericArgument(),
- QGenericArgument val2 = QGenericArgument(),
- QGenericArgument val3 = QGenericArgument(),
- QGenericArgument val4 = QGenericArgument(),
- QGenericArgument val5 = QGenericArgument(),
- QGenericArgument val6 = QGenericArgument(),
- QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument());
- static inline bool invokeMethod(QObject *obj, const char *member,
- QGenericReturnArgument ret,
- QGenericArgument val0 = QGenericArgument(0),
- QGenericArgument val1 = QGenericArgument(),
- QGenericArgument val2 = QGenericArgument(),
- QGenericArgument val3 = QGenericArgument(),
- QGenericArgument val4 = QGenericArgument(),
- QGenericArgument val5 = QGenericArgument(),
- QGenericArgument val6 = QGenericArgument(),
- QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument())
- {
- return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3,
- val4, val5, val6, val7, val8, val9);
- }
- static inline bool invokeMethod(QObject *obj, const char *member,
- Qt::ConnectionType type,
- QGenericArgument val0 = QGenericArgument(0),
- QGenericArgument val1 = QGenericArgument(),
- QGenericArgument val2 = QGenericArgument(),
- QGenericArgument val3 = QGenericArgument(),
- QGenericArgument val4 = QGenericArgument(),
- QGenericArgument val5 = QGenericArgument(),
- QGenericArgument val6 = QGenericArgument(),
- QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument())
- {
- return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2,
- val3, val4, val5, val6, val7, val8, val9);
- }
- static inline bool invokeMethod(QObject *obj, const char *member,
- QGenericArgument val0 = QGenericArgument(0),
- QGenericArgument val1 = QGenericArgument(),
- QGenericArgument val2 = QGenericArgument(),
- QGenericArgument val3 = QGenericArgument(),
- QGenericArgument val4 = QGenericArgument(),
- QGenericArgument val5 = QGenericArgument(),
- QGenericArgument val6 = QGenericArgument(),
- QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument())
- {
- return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0,
- val1, val2, val3, val4, val5, val6, val7, val8, val9);
- }
- QObject *newInstance(QGenericArgument val0 = QGenericArgument(0),
- QGenericArgument val1 = QGenericArgument(),
- QGenericArgument val2 = QGenericArgument(),
- QGenericArgument val3 = QGenericArgument(),
- QGenericArgument val4 = QGenericArgument(),
- QGenericArgument val5 = QGenericArgument(),
- QGenericArgument val6 = QGenericArgument(),
- QGenericArgument val7 = QGenericArgument(),
- QGenericArgument val8 = QGenericArgument(),
- QGenericArgument val9 = QGenericArgument()) const;
- enum Call {
- InvokeMetaMethod,
- ReadProperty,
- WriteProperty,
- ResetProperty,
- QueryPropertyDesignable,
- QueryPropertyScriptable,
- QueryPropertyStored,
- QueryPropertyEditable,
- QueryPropertyUser,
- CreateInstance
- };
- int static_metacall(Call, int, void **) const;
- static int metacall(QObject *, Call, int, void **);
- #ifdef QT3_SUPPORT
- QT3_SUPPORT const char *superClassName() const;
- #endif
- struct { // private data
- const QMetaObject *superdata; // 父類
- const char *stringdata; // 類名
- const uint *data; // 任意指向數據的指針
- const void *extradata; // 擴展數據
- } d;
- };
QMetaObject就內部一個結構體對象,包含了四個部分,分別是父類對象,自己元對象的名稱,以及一個指針任意值的指針數據和擴展數據,一般情況下,d.data表示的是QMetaObjectPrivate對象指針,在priv函數中可以找到一些痕跡:
- static inline const QMetaObjectPrivate *priv(const uint* data)
- { return reinterpret_cast<const QMetaObjectPrivate*>(data); }
按照Qt的實現慣例,使用Private對象做一些具體的工作,於是就有了QMetaObjectPrivate和QObjectPrivate
- struct QMetaObjectPrivate // 注意是一個結構體
- {
- int revision; // 版本
- int className; // 類名,注意類型
- int classInfoCount, classInfoData; // 類信息數據和數量
- int methodCount, methodData; // 方法數據和數量
- int propertyCount, propertyData; // 屬性數據和數量
- int enumeratorCount, enumeratorData; // 枚舉數據和數量
- int constructorCount, constructorData; //since revision 2 // 構造函數數據和數量
- int flags; //since revision 3 // 標記
- int signalCount; //since revision 4 // 信號量數目
- // revision 5 introduces changes in normalized signatures, no new members
- // 從元數據中獲取QMetaObjectPrivate對象指針,從data中得到!!
- static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
- { return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); }
- static int indexOfSignalRelative(const QMetaObject **baseObject,
- const char* name,
- bool normalizeStringData);
- static int indexOfSlot(const QMetaObject *m,
- const char *slot,
- bool normalizeStringData);
- static int originalClone(const QMetaObject *obj, int local_method_index);
- #ifndef QT_NO_QOBJECT
- //defined in qobject.cpp
- enum DisconnectType { DisconnectAll, DisconnectOne };
- static bool connect(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index,
- int type = 0, int *types = 0);
- static bool disconnect(const QObject *sender, int signal_index,
- const QObject *receiver, int method_index,
- DisconnectType = DisconnectAll);
- static inline bool disconnectHelper(QObjectPrivate::Connection *c,
- const QObject *receiver, int method_index,
- QMutex *senderMutex, DisconnectType);
- #endif
- };
==================================================================
- class Q_CORE_EXPORT QObjectPrivate : public QObjectData
- {
- Q_DECLARE_PUBLIC(QObject)
- public:
- struct ExtraData // 定義額外數據
- {
- ExtraData() {}
- #ifndef QT_NO_USERDATA
- QVector<QObjectUserData *> userData;
- #endif
- QList<QByteArray> propertyNames; // 屬性名列表
- QList<QVariant> propertyValues; // 屬性值
- };
- struct Connection // 定義連接信息
- {
- QObject *sender; // 發送者
- QObject *receiver; // 接受者
- int method; // 方法
- uint connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
- QBasicAtomicPointer<int> argumentTypes; // 參數類型
- // The next pointer for the singly-linked ConnectionList
- Connection *nextConnectionList; // 下一個連接對象列表
- //senders linked list
- Connection *next; // 下一個連接
- Connection **prev; // 上一個連接
- ~Connection();
- };
- // ConnectionList is a singly-linked list
- struct ConnectionList { // 定義連接列表
- ConnectionList() : first(0), last(0) {}
- Connection *first; // 連接首
- Connection *last; // 連接尾
- };
- struct Sender // 定義發送者
- {
- QObject *sender; // 發送者
- int signal; // 信號
- int ref; // 引用計數
- };
- QObjectPrivate(int version = QObjectPrivateVersion);
- virtual ~QObjectPrivate();
- void deleteChildren(); // 刪除所有子節點
- void setParent_helper(QObject *); // 設置父節點
- void moveToThread_helper(); // 轉到某個線程中
- void setThreadData_helper(QThreadData *currentData, QThreadData *targetData); // 設置線程數據
- void _q_reregisterTimers(void *pointer); // 設置註冊時間
- bool isSender(const QObject *receiver, const char *signal) const; // 判斷信號量是否爲發送者
- QObjectList receiverList(const char *signal) const; // 接受信號的對象列表
- QObjectList senderList() const; // 發出信息列表
- void addConnection(int signal, Connection *c); // 添加一個信號連接
- void cleanConnectionLists(); // 清理連接列表
- #ifdef QT3_SUPPORT
- void sendPendingChildInsertedEvents();
- void removePendingChildInsertedEvents(QObject *child);
- #endif
- static inline Sender *setCurrentSender(QObject *receiver,
- Sender *sender); // 設置當前發送者
- static inline void resetCurrentSender(QObject *receiver,
- Sender *currentSender,
- Sender *previousSender); // 重置當前發送者
- static int *setDeleteWatch(QObjectPrivate *d, int *newWatch); // 設置刪除監聽
- static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch); // 重置刪除監聽
- static void clearGuards(QObject *); // 清除管理者
- static QObjectPrivate *get(QObject *o) { // 從QObject對象中獲取QObjectPrivate
- return o->d_func();
- }
- int signalIndex(const char *signalName) const; // 信號索引
- inline bool isSignalConnected(uint signalIdx) const; // 判斷是否爲信號連接
- public:
- QString objectName; // 對象名字
- ExtraData *extraData; // extra data set by the user // 額外數據
- QThreadData *threadData; // id of the thread that owns the object // 線程數據
- QObjectConnectionListVector *connectionLists; // 連接列表數組
- Connection *senders; // linked list of connections connected to this object // 發送者連接
- Sender *currentSender; // object currently activating the object // 當前發送者
- mutable quint32 connectedSignals[2]; // 連接信號
- #ifdef QT3_SUPPORT
- QList<QObject *> pendingChildInsertedEvents;
- #else
- // preserve binary compatibility with code compiled without Qt 3 support
- // keeping the binary layout stable helps the Qt Creator debugger
- void *unused; // 保留
- #endif
- QList<QPointer<QObject> > eventFilters;
- union {
- QObject *currentChildBeingDeleted; // 當前子節點被刪除
- QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
- };
- // these objects are all used to indicate that a QObject was deleted
- // plus QPointer, which keeps a separate list
- QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount; // 共享引用計數
- int *deleteWatch; // 刪除監聽者
- };
QObjectPrivate從QObjectData派生下來:
- class
- #if defined(__INTEL_COMPILER) && defined(Q_OS_WIN)
- Q_CORE_EXPORT
- #endif
- QObjectData {
- public:
- virtual ~QObjectData() = 0;
- QObject *q_ptr; // 當前指向的QOBject
- QObject *parent; // 指向的QObject父類
- QObjectList children; // 孩兒們
- uint isWidget : 1; // 是否爲widget的標記
- uint pendTimer : 1; // 開啓時鐘
- uint blockSig : 1; // 阻塞信號標記
- uint wasDeleted : 1; // 是否參數標記
- uint ownObjectName : 1; // 是否含有對象名標記
- uint sendChildEvents : 1; // 發送到子對象時間標記
- uint receiveChildEvents : 1; // 接受子對象時間標記
- uint inEventHandler : 1; // 是否有事件句柄標記
- uint inThreadChangeEvent : 1; // 線程更改時間標記
- //是否有守護標記
- uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
- uint unused : 22; // 保留
- int postedEvents; // 發送的數據
- QMetaObject *metaObject; // assert dynamic // 元對象
- };
QObjectData保留一些了基本的數據信息
- #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;
在元對象中獲取類名和父類的方式很簡單,直接即可。
- inline const char *QMetaObject::className() const
- { return d.stringdata; }
- inline const QMetaObject *QMetaObject::superClass() const
- { return d.superdata; }
元對象中cast函數的實現
- QObject *QMetaObject::cast(QObject *obj) const
- {
- if (obj) {
- const QMetaObject *m = obj->metaObject();
- do {
- if (m == this)
- return const_cast<QObject*>(obj);
- } while ((m = m->d.superdata));
- }
- return 0;
- }
如果對象obj存在,則對每一個obj的父類的源對象進行轉換,如果是當前的元對象,則進行返回,否則返回0,也就是cast函數是在obj中查找當前元對象所在的QObject對象。