Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么
这篇文章主要介绍“Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么”,在日常操作中,相信很多人在Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
问题代码:
sender.h
class Sender : public QObject { Q_OBJECT public: explicit Sender(QObject *parent = nullptr); enum eResult { kSuccess, kFail, }; signals: void loginResult(eResult result); void otherSignal(QString str); };
定义了两个信号:
loginResult() 这个信号采用 eResult 作为参数,而 eResult 是 Sender 类内部定义的类型;
otherSignal() 作为参照,使用Qt所定义的类型的信号。
receiver.h
class Receiver : public QObject { Q_OBJECT public: explicit Receiver(QObject *parent = nullptr); signals: public slots: void onLoginResult(Sender::eResult result); void onOtherSignal(QString str); private: Sender *sender_; };
在 Receiver 中定义了两个slot分别接收 Sender 的两个信号。
在 Receiver 的构造函数中:
Receiver::Receiver(QObject *parent) : QObject(parent) , sender_(new Sender()) { connect(sender_, SIGNAL(loginResult(Sender::eResult)), this, SLOT(onLoginResult(Sender::eResult))); connect(sender_, SIGNAL(otherSignal(QString)), this, SLOT(onOtherSignal(QString))); }
结果在运行时报错:
提示信号没有连接上。
如果我们将 eResult 放到 Sender 类外面,则没有这个问题。
这是为什么呢?
是不是只要是类内部的类型都会出错?
为了排除是我们自定义的枚举的原因,我们把自己定义的 eResult 改成 MyString,其它也对应改过来。
再试:
结果还是报错:
这也证定了我的猜想。为是什么呢?
打开自动生成的 moc_sender.cpp 文件看看里面的内容:
如果我们再加一个signal:
moc_sender.cpp 中会发生什么样的变化呢?
(1)字面量里多出两个新的字面量。
(2)在 qt_meta_data_Sender 中也多出些新的描述:
可以看出,qt_meta_data_Sender 中可以描述出一个 QObject 类有哪些信号函数。每个信号函数的返回类型与参数各为什么。
从上可以看到,qt_meta_data_Sender 中记录的信号自定义的参数类型idx指向的是 MyString。我们在 Receiver 中 connect() 使用的是 Sender::MyString。会不会是两者对不上号导致的呢?
如果我们改成这样:
把 Sender:: 前缀加上。
看看会不会成功了呢?结果没有再报错了。
我们再来看看 moc_sender.cpp 的变化:
猜想:
在下面的 connect() 代码中:
SIGNAL() 宏把
预编译成 "loginResult(Sender::MyString)" 的字符串。在执行时,就会拿着该字串去 Sender 对象中找信号名为 "loginResult" 参数个数只有一个,参数类型名为 "Sender::MyString" 的信号进行连接。
如果我们在 Sender 中将 loginResult 信号的参数类型写成 MyString 而不是写全 Sender::MyString,那么在 connect() 时,它就不能在 Sender 的 qt_meta_data_Sender 中找到这个信号,所以就失败了。
如果我们还是采用原来的做法:
而在 connect() 的地方,直接写 MyString,而不写成 Sender::MyString,如下:
执行报错:
说是不兼容的参数类型。
可能 connect() 函数在入口处,就对参数signal与slot的参数类型字串进行比较,如果不一致,那么就会认为错误。
那反过来,我们在 connect() 时将 slot 的参数写成:
执行结果:
如果我们把 Receive::onLoginResult() 的参数类型改成 MyString 呢?
如下:
编译通过,运行时 connect() 正常。
是不是它只认类型的名称,不做类型推导呢?
我们大胆地做一个尝试:
我们给 MyString 乱指定一个类型。
结果编译通过,运行时 connect() 正常。
从本质上 MyString 就是 QString 的别名。
如果在 Receive 端使用 QString 替代 MyString 是不是就不能 connect() 成功了呢?
如下修改:
编译正常,运行结果:
这个实验足于证明,connect() 只管类型名称的比效,完全不做任何的类型推导。
综上结论:
在执行 QObject::connect() 时,它会对signal与slot参数的名称进行对比,只有名称完会一致的才能连接上,否会不失败。
值得注意的是:它只管对类型的名称进行比较,完全不会做任何的类型推导与类型检查。
到此,关于“Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!