Q_OBJECT宏展开
#define Q_OBJECT \
public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \virtual const QMetaObject *metaObject() const; \virtual void *qt_metacast(const char *); \virtual int qt_metacall(QMetaObject::Call, int, void **); \QT_TR_FUNCTIONS \
private: \Q_OBJECT_NO_ATTRIBUTES_WARNING \Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \QT_WARNING_POP \struct QPrivateSignal {}; \QT_ANNOTATE_CLASS(qt_qobject, "")
- QMetaObject类的作用是为QObject子类存储所有的元信息;还维护类的信号和槽之间的对应表,以及任何连接的类的信号和槽对应表。每一个信号槽都被分配了一个唯一的索引:
- metaObject()函数对于普通的Qt类返回&staticMetaObject;处理QML对象返回dynamicMetaObject
- qt_metacast()函数使用类的名称进行动态转换。这个函数是必须的,因为Qt不依赖标准C++RTTI(运行时类型信息)来检索关于一个对象或一个类的元数据
- qt_metacast()直接通过索引调用一个内部信号或槽。因为使用的是索引而不是指针,所以没有指针的指针解读,生成的switch case可以被编译器大量优化(编译器可以在很早的时候直接包含跳转指令到特定的情况,避免大量的分支评估)。因此,信号/槽机制的执行是相当快的
siganls/slots/emit
-
定义
#define slots #define signals public #define emit
-
当一个信号关键词被发射,QMetaObject::activate()被调用并带有改变的值和信号索引
-
QObject::connect():创建一个新的Connection,在qobject_p.h定义
struct Connection
{QObject *sender;QObject *receiver;union {StaticMetaCallFunction callFunction;QtPrivate::QSlotObjectBase *slotObj;};// The next pointer for the singly-linked ConnectionListConnection *nextConnectionList;//senders linked listConnection *next;Connection **prev;//...
};
- Connection实例存储了一个指向信号发射器类(sender)、槽接收器类(receiver)的指针,及连接的信号槽关键字的索引。当一个信号被发射出去,每一个连接的槽都必须被调用。为了能做到这一点,每一个QObject为它每个信号都有一个Connection实例的链接列表,它的每个槽关键字也有同样的Connection链接列表
- 这对链接列表允许Qt正确地走到每个依赖槽/信号对,以使用索引触发正确的函数。同理处理接收器的销毁。Qt走过双链接列表,将对象从它连接的地方删除
- 这些机制发生在UI线程中。因为QThread类继承了QObject,任何QThread都可以使用信号/槽机制