一条狗的使命 百度云Qtconnect的实现原理
概述
connect实质上是将对象A的信号和对象B的槽函数进⾏连接,然后返回⼀个句柄Connection。
正⽂
下⾯通过源码来解析⼀下:(注意看中⽂注释)
// connection表⽰信号槽连接句柄
QMetaObject::Connection QObject::connect(const QObject *nder,const char*signal,
const QObject *receiver,const char*method,
still是什么意思Qt::ConnectionType type)
{
// 校验对象的信号和槽
if(nder ==nullptr|| receiver ==nullptr|| signal ==nullptr|| method ==nullptr){
qWarning("QObject::connect: Cannot connect %s::%s to %s::%s",
youth青春nder ? nder->metaObject()->className():"(nullptr)",
(signal &&*signal)? signal+1:"(nullptr)",
receiver ? receiver->metaObject()->className():"(nullptr)",
(method &&*method)? method+1:"(nullptr)");
return QMetaObject::Connection(nullptr);
}
QByteArray tmp_signal_name;
if(!check_signal_macro(nder, signal,"connect","bind"))
return QMetaObject::Connection(nullptr);
const QMetaObject *smeta = nder->metaObject();// 发送者元对象
工资翻番const char*signal_arg = signal;
++signal;//skip code
QArgumentTypeArray signalTypes;
Q_ASSERT(QMetaObjectPrivate::get(smeta)->revision >=7);中秋节翻译
QByteArray signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);// 获取信号签名(就是转成字符串)
// 通过发送者元对象获取信号的索引
北京火星时代int signal_index = QMetaObjectPrivate::indexOfSignalRelative(
&smeta, signalName, signalTypes.size(), stData());
if(signal_index <0){
// 重新校验前⾯然后获取信号的索引
// check for normalized signatures
tmp_signal_name = QMetaObject::normalizedSignature(signal -1);
signal = tmp_stData()+1;
alternativetosignalTypes.clear();
signalName = QMetaObjectPrivate::decodeMethodSignature(signal, signalTypes);
smeta = nder->metaObject();
signal_index = QMetaObjectPrivate::indexOfSignalRelative(
&smeta, signalName, signalTypes.size(), stData());
}
if(signal_index <0){
中国梦演讲稿教师篇
// 没有索引,返回空句柄
err_method_notfound(nder, signal_arg,"connect");
err_info_about_objects("connect", nder, receiver);
return QMetaObject::Connection(nullptr);
}
signal_index = QMetaObjectPrivate::originalClone(smeta, signal_index);// 获取原⽣⽅法的索引(例如传递destroyed()的索引,则返回destroyed(QObject*)的索引
signal_index += QMetaObjectPrivate::signalOfft(smeta);
QByteArray tmp_method_name;
int membcode =extract_code(method);// 获取⽅法code
// 校验⽅法code,如果该⽅法code不属于信号和槽函数,则返回空句柄
if(!check_method_code(membcode, receiver, method,"connect"))
return QMetaObject::Connection(nullptr);
const char*method_arg = method;
++method;// skip code
QArgumentTypeArray methodTypes;
QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);// 获取⽅法签名(格式和信号前⾯⼀致)const QMetaObject *rmeta = receiver->metaObject();// 接收者元对象
int method_index_relative =-1;
Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >=7);
// 下⾯是获取信号或槽函数的相对索引
switch(membcode){
ca QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
&rmeta, methodName, methodTypes.size(), stData());
break;
ca QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
&rmeta, methodName, methodTypes.size(), stData());
break;
}
if(method_index_relative <0){
// check for normalized methods
tmp_method_name = QMetaObject::normalizedSignature(method);
method = tmp_stData();
methodTypes.clear();
methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes);
// rmeta may have been modified above
rmeta = receiver->metaObject();
switch(membcode){
ca QSLOT_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSlotRelative(
&rmeta, methodName, methodTypes.size(), stData());
break;
ca QSIGNAL_CODE:
method_index_relative = QMetaObjectPrivate::indexOfSignalRelative(
&rmeta, methodName, methodTypes.size(), stData());
break;
}
}
if(method_index_relative <0){
tightrr_method_notfound(receiver, method_arg,"connect");
err_info_about_objects("connect", nder, receiver);
return QMetaObject::Connection(nullptr);
}
// 校验信号和槽的参数
if(!QMetaObjectPrivate::checkConnectArgs(signalTypes.size(), stData(),
methodTypes.size(), stData())){
qWarning("QObject::connect: Incompatible nder/receiver arguments"
"\n %s::%s --> %s::%s",
nder->metaObject()->className(), signal,
receiver->metaObject()->className(), method);
return QMetaObject::Connection(nullptr);
}
// 当链接类型为队列时需要检测信号参数的类型是否为元类型,不是的话需要注册,没有注册就⽆法链接
int*types =nullptr;
if((type == Qt::QueuedConnection)
&&!(types =stData(), signalTypes.size()))){
return QMetaObject::Connection(nullptr);
}
#ifndef QT_NO_DEBUG
QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
QMetaMethod rmethod = rmeta->method(method_index_relative + rmeta->methodOfft());
check_and_warn_compat(smeta, smethod, rmeta, rmethod);
#endif
// 句柄包含了发送者、信号索引、发送者元对象、接收者、槽函数索引、接收者元对象、链接类型、参数类型
诧异什么意思QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
nder, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
return handle;
}
总结来说,connect前⾯主要是进⾏校验发送者、信号索引、接收者、槽函数索引、链接类型以及参数类型。都校验成功时,返回句柄。connection句柄是⾮常有⽤的,⾥⾯包含了发送者、信号索引、发送者元对象、接收者、槽函数索引、接收者元对象、链接类型、参数类型;后续在执⾏信号函数的时候会检索对应信号的所有信息。