内容简介:上次和大家分享的是Qt信号和槽的一些宏定义以及元对象编译器。这次和大家分享信号和槽的很多讲Qt信号和槽的文章都会讲到元对象编译器生成的代码,也就是以一、connect
上次和大家分享的是Qt信号和槽的一些宏定义以及元对象编译器。这次和大家分享信号和槽的 connect 函数到底连接了什么、还有元对象编译器都生成了什么代码。
很多讲Qt信号和槽的文章都会讲到元对象编译器生成的代码,也就是以 moc_ 为前缀的 .cpp 文件,本例子中是在编译后 Debug 目录的 moc_counter.cpp 文件。当时我看了好多遍,最后还是没有很好的理解,随后就顺着信号和槽的执行过程进行理解。
一、connect
使用信号和槽之前,必须使用connect将信号和槽连接起来,那么在内部究竟都做了些什么呢?
首先connect是一个重载函数,我们最常使用的则是四个参数的调用,即默认连接类型为 AutoConnection ,也就是下面这个样子:
QMetaObject::Connection connect(const QObject * sender, const char * signal,
const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection)
之前说过SIGNAL和 SLOT 关键字,也就是说上次例子中的连接其实是这个样子:
QObject::connect(&a, 2signal_valueChanged(int),
&b, 1slot_setValue(int));
OK,接下来看一个连接所需要的信息,下面是一个简化过的数据。 Qt 更高的版本中又对数据进行了抽象。
struct QObjectPrivate::Connection
{
QObject *sender;
QObject *receiver;
union {
StaticMetaCallFunction callFunction;
QtPrivate::QSlotObjectBase *slotObj;
};
// 单独连接的 ConnectionList 的 next 指针
Connection *nextConnectionList;
// senders 链表
Connection *next;
Connection **prev;
QAtomicPointer argumentTypes;
QAtomicInt ref_;
ushort method_offset;
ushort method_relative;
uint signal_index : 27; // 信号范围(参考 QObjectPrivate::signalIndex())
ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
ushort isSlotObject : 1;
ushort ownArgumentTypes : 1;
Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) {
// ref_ 赋值为 2,以便内部列表使用,同时供 QMetaObject::Connection 使用
}
~Connection();
int method() const { return method_offset + method_relative; }
void ref() { ref_.ref(); }
void deref() {
if (!ref_.deref()) {
Q_ASSERT(!receiver);
delete this;
}
}
};
可以查一查C++中结构体与类的区别与联系。
简单对里面的部分数据进行说明,如果遇到元对象编译器生成的代码再做扩展说明。
首先一个连接里面会存储发送对象与接收对象;
callFunction 是接收端的私有静态函数 qt_static_metacall() 【 Q_OBJECT 宏中定义,由元对象编译器实现】,这个接收端私有静态函数是可以根据相对序号 ( 索引 ) 调用元方法的。该方法通过对索引计算就可以访问到对应的槽函数了,以后有机会再做详解。
元对象编译器扩展部分:
相对序号(索引 ) 与元方法:
在每一个 QMetaObject 中,槽、信号以及其它该对象可调用的函数都会分配一个从 0 开始的索引。它们是有顺序的,信号在第一位,然后是槽,最后是其它函数。这个索引在内部被称为 相对索引。它们不包含父对象的索引。
Qt中常见的元方法就是信号和槽,其他不做扩展。
nextConnectionList 是下一个链表节点,由同样的 Connection 填充;
最终会构成如下的结构:
一个对象可能有多个信号,Qt的 MedaObject 会把信号组装成一个 Signal Vector ,每个 signal 都可以根据序号 ( 索引 ) 来获得;每个信号都会维护一个要触发槽的链表,当一个 Signal 被调用时,对应链表内所有的槽都会被触发【以前看过当一个信号连接多个槽时,槽是被随机触发的,通过源码来看,一个信号对应的多个槽是按加入链表顺序来触发的,有机会做下验证】。
二、 小结
简单来说,一个connect就是存储了接口类 (QObject) 的一些信息,通过这些信息以及 Qt 的对象树模型再加上序号索引就可以快速找到一个信号所连接接口对象对应的槽函数。
这里面没和大家说字符串表以及内省表,有兴趣的话大家可以想一想这两个表在Qt元对象系统中究竟扮演了什么角色。
刚开始看这些信息可能会晕晕乎乎的,多看几遍,结合自己的疑问,很快就会理顺。
记录了自己成长的点点滴滴。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 树莓派基础-模拟信号和数字信号的区别
- xenomai内核解析之信号signal(二)---xenomai信号处理机制
- 没信号也可救你命:苹果新专利让iPhone无信号也可充当紧急信标
- 信号量
- flask---信号
- Python信号处理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Spring揭秘
王福强 / 人民邮电出版社 / 2009.8 / 99.00元
没有教程似的训导,更多的是说故事般的娓娓道来,本书是作者在多年的工作中积累的第一手Spring框架使用经验的总结,深入剖析了Spring框架各个模块的功能、出现的背景、设计理念和设计原理,揭开了Spring框架的神秘面纱,使你“知其然,更知其所以然”。每部分的扩展篇帮助读者活学活用Spring框架的方方面面,同时可以触类旁通,衍生出新的思路和解决方案。 本书内容全面,论述深刻入理,必将成为每......一起来看看 《Spring揭秘》 这本书的介绍吧!