千家信息网

Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么

发表于:2024-11-21 作者:千家信息网编辑
千家信息网最后更新 2024年11月21日,这篇文章主要介绍"Qt signal函数使用类内部类型作为参数导致connect不成功的原因是什么",在日常操作中,相信很多人在Qt signal函数使用类内部类型作为参数导致connect不成功的原
千家信息网最后更新 2024年11月21日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不成功的原因是什么"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0