Qt:子类中无法识别继承的信号

Posted

技术标签:

【中文标题】Qt:子类中无法识别继承的信号【英文标题】:Qt: inherited signal not recognized in subclass 【发布时间】:2013-05-17 08:43:03 【问题描述】:

我创建了一个为所有子类提供公共信号的基类:

#include <QWidget>

namespace Dino 

/**
 * @brief Base class for all single-value settings editors
 *
 * Provides a valueChanged() signal that can be used to propagate changes to
 * values up to the MainWindow
 */
class TypeEditor : public QWidget

    Q_OBJECT
public:
    explicit TypeEditor(QWidget *parent = 0):QWidget(parent)

signals:
    void valueChanged();    
;

 // namespace Dino

在一个子类中,我想让这个信号可用,但也定义一个更具体的信号,名称相同但参数不同:

#include "ui/typeeditor.h"

namespace Dino 

class BoolEditor : public TypeEditor

    Q_OBJECT
public:
    explicit BoolEditor(QWidget* parent = 0):TypeEditor(parent)

signals:
    void valueChanged(bool value);

public slots:
    void setValue(bool value)
    
        emit valueChanged(value);
        emit valueChanged();
    
;

 // namespace Dino

想法是,当只知道基类类型时,可以使用泛化信号,这说明值发生了变化。当确切的子类类型已知时,另一个信号可用,它告诉新值。

现在,当我尝试编译时,emit valueChanged() 上出现错误,指出没有名为 Dino::BoolEditor::valueChanged() 的函数。

当我将基类中的信号重命名为其他名称时,它可以工作,所以这似乎是信号重载的问题。我会对这样做的原因感兴趣。是我不知道的一些设计要求阻止了我在子类中重载信号,还是我只是在代码中遗漏了一些东西?

【问题讨论】:

【参考方案1】:

信号只是一个受保护的功能。你不能像那样重载基类函数

详情请见this question

【讨论】:

谢谢。我没有意识到这一点。不知何故,我以前从未发生过这样的事情,即使不使用 Qt 也是如此。我认为编译器必须注意到不带参数的基类函数是唯一匹配这里的函数。愚蠢的我假设编译器中的智能比现有的更多。感谢您链接其他问题。它有一些有见地的答案。【参考方案2】:

这是 C++ 中的重载方法。试试:

emit TypeEditor::valueChanged();

【讨论】:

谢谢。我之前确实尝试过,但认为编译器必须足够智能才能自行解决。【参考方案3】:

是信号过载的问题。

首先,您的问题是 C++ 问题,而不是 Qt 问题。那么在你的情况下,你不能说重载。

如果您在派生类中定义了与基类方法具有相同名称和签名的方法,那么您正在重载。如果你有 b->valueChanged(),这个信号没有在基类中定义参数,你不会得到编译错误。

编译代码时,编译器会在最近的范围内寻找 valueChanged() 信号,即 B 类的范围。他找到一个 valueChanged(bool) 然后检查参数列表。由于没有匹配,所以有编译错误。

【讨论】:

重载只需要相同的函数名,不需要相同的签名(en.wikipedia.org/wiki/Function_overloading)。你指的是覆盖(en.wikipedia.org/wiki/Method_overriding)。【参考方案4】:

您所做的称为“隐藏”或“隐藏”名称。当编译器将继承层次结构复制到基类中时(我知道还有更多,我只是在简化),它首先会在当前范围内查看是否有同名的东西。如果它可以找到与您正在查找的名称(不是签名或类型)相同的成员,那么即使继承层次结构中有更好的候选者,它也不会再查找!

那么,你如何解决这个问题?您可以使用using 语句将声明从父类导入派生类。 (你可以看到更多关于这个here。)

例如:

struct A 
    int f()  return 42; 
;

struct B : A 
    using A::f; // <- This is the magic line!
    int f(int n)  return 42 + n; 
;

派生类中的using A::f; 语句将A 中的f 成员添加到当前作用域中,现在这两个函数都可见并且可以使用了!

Here 是 ideone 上的一个可运行示例。

【讨论】:

很抱歉以这种方式与您联系(我的评论与您在此处的输入无关)。我遇到了一个你在“分类”中投票的问题,你做出了错误的选择。请:仔细研究分类帮助,避免将不属于那里的项目放入编辑队列。我希望您将此视为改善投票的机会。我特指***.com/review/triage/21072947。如果您对我有其他问题或反馈,请随时给我留言。如果你给我一个快速的回复,我会立即在这里评论。

以上是关于Qt:子类中无法识别继承的信号的主要内容,如果未能解决你的问题,请参考以下文章

Qt4 现有插槽无法识别

Qt 无法识别标准库

在 Qt 应用程序中似乎无法识别插槽 [重复]

QT 信号和槽链接时注意事项

Qt 5.0.1 中的“配置”无法识别

iBeacon 接收器无法识别传输的信号