Q_OBJECT
所有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对象。
Q_OBJECT的更多相关文章
- Qt - 错误总结 - 在自定义类头文件中添加Q_OBJECT 编译时报错(undefined reference to ‘vtable for xxThread)
错误提示:在添加的QThread子类头文件添加Q_OBJECT时,编译程序,出现"undefined reference to 'vtable for xxThread'"错误提示 ...
- qt中添加Q_OBJECT报错的问题
在qt编写的过程中添加Q_OBJECT后发现老是报错的问题 编译后老是报undefined reference to vtable for "xxx"的错误,后来发现在xxx.pr ...
- QT宏 Q_OBJECT,explicit, QHostAddress, quint, emit
QT相關 一. 參考: 1.宏Q_OBJECT 二. explicit struct constrcution 三. QHostAddress Detailed Description: The QH ...
- 气死人不偿命,Q_OBJECT导致的C++报错,而且还看不明白(#ifdef没控制好,导致什么都不认识了)
为了代码可以同时适应VC++和MingW编译器,我改动了我的代码,变成: #ifdef _MSC_VER #pragma comment(lib, "crypt32.lib") / ...
- cmake+qt+qtcreator的配置,解决Q_OBJECT的问题
1.如果在编译qt项目的时候,一般头文件里都有Q_OBJECT,但是用cmake来编译的时候,就会报错,那么怎么解决呢? 解决的办法就是要在cmake里面写好配置 命令,再编译的时候,就不会报错了,写 ...
- Qt错误:类中使用Q_OBJECT宏导致undefined reference to vtable for "xxx::xxx"错误的原因和解决方法
在进行Qt编程的时候,有时候会将类的定义和实现都写在源文件中,如果同时在该类中使用信号/槽,那么可能就会遇到 undefined reference to vtable for "xxx:: ...
- Qt5 在添加 Q_OBJECT 后发现编译出错的原因
在 Qt 编写过程中,如多线程使用信号槽时,需要添加 Q_OBJECT,但是在添加之后发现编译老会出错.如下: class ThreadSxxx : public QThread { Q_OBJECT ...
- 读QT5.7源码(三)Q_OBJECT 和QMetaObject
Qt meta-object系统基于三个方面: 1.QObject提供一个基类,方便派生类使用meta-object系统的功能: 2.Q_OBJECT宏,在类的声明体内激活meta-object功 ...
- Quest for sane signals in Qt - step 1 (hand coding a Q_OBJECT)
探索qt的信号ref: http://crazyeddiecpp.blogspot.hk/2011/01/quest-for-sane-signals-in-qt-step-1.html If it ...
随机推荐
- Redis配置文件参数说明
Redis配置文件参数说明 1. Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 2. 当Redis以守护进程方式运行时,Redis ...
- 42、lucene和机器学习进行全文搜索,并排序
package com.lucene.test; import java.io.BufferedInputStream; import java.io.File; import java.io.Fil ...
- 动态设置和访问cxgrid列的Properties(转)
原文:http://www.cnblogs.com/hnxxcxg/archive/2010/05/24/2940711.html 动态设置和访问cxgrid列的Properties 设置: cxGr ...
- Des加解密算法
class DesHelper { /// <summary> /// DES加密方法 /// </summary> ...
- web聊天室
开发一个web聊天室 功能需求: 1.用户可以与好友一对一聊天 2.群聊 所需知识 1.Django 2.bootstrap 3.CSS 4.ajax 涉及到的新的知识点 1.如果设计表结构的时候,一 ...
- Roguelike 相关知识
here is the link here
- 关于设置anroid系统时间
我最近在做一个项目需要设置android系统时间,设置android 时间往往缺少权限,看到http://blog.csdn.net/kakaxi1o1/article/details/3687278 ...
- 用于模式匹配的String方法
String支持四种使用正则表达式的方法. 1.search()返回第一个与之匹配的子串的起始位置,找不到返回-1.search()参数是一个正则表达式,如果参数不是正则表达式,则会先通过RegExp ...
- 删除表空间的时候遇到的问题:ORA-02429: 无法删除用于强制唯一/主键的索引
今天打算删除orcale数据库中无用的表空间,发现报错,查资料删除,写个过程留着备用.1.drop tablespace dldata INCLUDING CONTENTS CASCADE CONST ...
- Struts2 有关于无法正常的使用通配符
今天使用struts 2.3.4版本,做了一个通配符的小测试,结果其他的Action都能正常的使用,但是使用通配符的Action不能正常的使用.网上找了很久,最后发现,貌似strust2.3版本以上的 ...