无法将Qt信号连接到自定义类成员函数

时间:2014-08-11 15:33:37

标签: c++ qt qt-signals

我目前正在Qt项目中工作,但我还没有太多关于Qt的经验,因此每次我被卡住时,我都会不时编码一些测试我不明白的事情。

我一直在研究的最后一个测试代码是QNetworkRequest包装器,用于存储网络请求,如下所示:

std::list<R> requests;
QNetworkRequest request(QUrl("http://awesome/web/api"));
requests.emplace_back(NetworkAccessManager.get(request), myCallback);

对象R如下所示:

首次尝试


struct R
{
    R(QNetworkRequest *const r, void (*cb)(QNetworkRequest *)) :
        m_r(r),
        m_cb(cb)
    {
        if (m_r)
        {
            // Error on line below
            QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);
        }
    }

private:

    void reply() { m_cb(m_r); }

    QNetworkRequest *const m_r;
    void (*m_cb)(QNetworkRequest *);
};

但我收到以下错误:

no matching function for call to 'QObject::connect(QNetworkRequest* const&, void (QNetworkReply::*)(), R* const, void (R::*)())'
         QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);

我不明白为什么连接不正确,我很确定之前做过类似的连接。

起初我怀疑错误与R不是QObject的事实有关,所以我做了以下更改:

第二次尝试


struct R
    : public QObject // <-- New!
{
    Q_OBJECT // <-- New!
    R(QNetworkRequest *const r, void (*cb)(QNetworkRequest *)) :
        m_r(r),
        m_cb(cb)
    {
        if (m_r)
        {
            // Error on line below
            QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);
        }
    }

private:

    void reply() { m_cb(m_r); }

    QNetworkRequest *const m_r;
    void (*m_cb)(QNetworkRequest *);
};

此更改会产生更多编译错误:

no matching function for call to 'R::connect(QNetworkRequest* const&, void (QNetworkReply::*)(), R* const, void (R::*)())'
         QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);

invalid use of incomplete type 'struct QtPrivate::QEnableIf<false, QMetaObject::Connection>'

declaration of 'struct QtPrivate::QEnableIf<false, QMetaObject::Connection>'
 template <bool B, typename T = void> struct QEnableIf;

所以我继续努力修复编译器错误(由于我缺乏Qt经验而非常盲目),我的下一个尝试是将方法R::reply()转换为插槽:

第三次尝试


struct R
    : public QObject
{
    Q_OBJECT
    R(QNetworkRequest *const r, void (*cb)(QNetworkRequest *)) :
        m_r(r),
        m_cb(cb)
    {
        if (m_r)
        {
            // Error on line below
            QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);
        }
    }

private slots: // <-- New!
    void reply() { m_cb(m_r); }
private:
    QNetworkRequest *const m_r;
    void (*m_cb)(QNetworkRequest *);
};

这根本不能解决问题,事实上,它产生与先前版本完全相同的错误。

所以我最后一次解决问题的方法是在connect指令上使用Qt宏:

上次尝试


struct R
    : public QObject
{
    Q_OBJECT
    R(QNetworkRequest *const r, void (*cb)(QNetworkRequest *)) :
        m_r(r),
        m_cb(cb)
    {
        if (m_r)
        {
            // Error on line below
            QObject::connect(m_r, SIGNAL(finished()), this, SLOT(reply()));
        }
    }

private slots:
    void reply() { m_cb(m_r); }
private:
    QNetworkRequest *const m_r;
    void (*m_cb)(QNetworkRequest *);
};

报告以下错误:

no matching function for call to 'R::connect(QNetworkRequest* const&, const char*, R* const, const char*)'
         QObject::connect(m_r, SIGNAL(finished()), this, SLOT(reply()));

no type named 'Object' in 'struct QtPrivate::FunctionPointer<const char*>'

invalid use of incomplete type 'struct QtPrivate::QEnableIf<false, QMetaObject::Connection>'

最后,我认为现在是停止猜测并开始寻求帮助的时候了:

  • 我第一次尝试时做错了什么?我非常确定可以将Qt信号与与QObject无关的类方法连接起来,我错了吗?
  • 其他尝试有什么不对?他们抱怨的不同于第一件事。
  • 为什么在上一次尝试connect签名使用const char*时,宏SIGNALSLOT正在将代码转换为字符?
  • 为了避免这样的问题,我们将不胜感激。

提前致谢。

3 个答案:

答案 0 :(得分:3)

您必须使用QNetworkAccessManager,因为它与QNetworkRequest不同,继承自QObject并且有finished信号,因此您可以连接到它。< / p>

但要回答你的第一个问题:

您必须使用Q_OBJECT宏并继承QObject才能使用信号和插槽机制。

避免类似问题的指南:

QNetworkRequest的文档没有说明有关finished广告位的任何内容,也没有说明为了使用信号和插槽而必须继承QObject

答案 1 :(得分:1)

您正在尝试连接来自不相关类QNetworkReply的对象的类QNetworkRequest的信号。

此外,QNetworkRequest不会继承QObject

  

为什么在上一次尝试connect签名使用const char*时,宏SIGNALSLOT正在将代码转换为字符?

是的,SIGNALSLOT宏扩展为C风格的字符串。

答案 2 :(得分:0)

我遇到了同样的问题,我在应用程序的其他地方找到了该解决方案,并且可以正常工作。

代替: QObject::connect(m_r, &QNetworkReply::finished, this, &R::reply);

写: QObject::connect(m_r, &QNetworkReply::finished, [=](){this->reply();});

相关问题