【问题标题】:Qt signals and slots: permissionsQt 信号和槽:权限
【发布时间】:2013-10-08 09:03:06
【问题描述】:

在 SO 和实际 Qt 文档中尊重的答案之间存在差异。

我已阅读this question,我想进一步澄清一下。谁能确认:

  • 信号总是protected,因此它只能由类或其任何子类发出。我不确定这是不是真的;上面的问题显示了支持这一说法的答案。但是Qt docs 说:Signals are public access functions and can be emitted from anywhere, but we recommend to only emit them from the class that defines the signal and its subclasses. 那么是哪个?
  • 插槽只是函数,因此可以是公共的、私有的或受保护的。显然,如果插槽是公共的,则外部类能够控制您的类是否将其自己的信号之一连接到其自己的插槽之一。但是,SO 信息再次与文档不同,文档中说:a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class. 这意味着信号/插槽机制不支持private
  • public、private、protected 这些词在使用 signal 关键字时没有用处
  • 发出的信号始终可供所有其他类使用,也就是说,任何其他类都可以始终连接到该信号(无论其发出信号的权限如何)。
  • 尽管所有类都可以查看所有信号,但由于connect 函数将类名作为信号前缀(即SomeClass::itsSignal),您仍然可以拥有两个具有相同名称的信号的类。

【问题讨论】:

  • 即使在 Qt4 中,您也可以使用 QMetaObject::invokeMethod 从类外发出信号

标签: c++ qt inheritance signals-slots qt-signals


【解决方案1】:
  • 信号在 Qt4 中受到保护,但在 Qt5 中是公开的,因此信息相互矛盾。
  • 插槽是函数,并且在调用它们时尊重公共/受保护/私有,但在连接到信号时,元对象系统会忽略它。
  • signals 定义为 public:,在它们前面加上例如私人线索

到:

private:
public: //signals:
    void theSignal();

所以没有效果。

  • 所有类都可以连接到任何信号,正确。在这方面,信号是公共 API 的一部分。
  • 具有相同的信号特征不是问题。上下文由指定为发送者的对象定义。

使用旧式连接:

Apple *apple ... Orange* orange
connect(apple, SIGNAL(changed()), this, SLOT(appleChanged()));
connect(orange, SIGNAL(changed()), this, SLOT(orangeChanged()));

信号在这里被指定为字符串(其中没有类名),但是appleorange每个只有一个信号changed(),并且查找是在QObject实例的元对象中完成的,它每个类(不是实例)存在一个,它们不能碰撞。

带有编译时检查的 Qt 5 版本:

connect(apple, &Apple::changed, this, &MyReceiver::appleChanged);

这里必须指定一个函数,因此根据范围,必须指定一个类名(可能还有命名空间)。由于模棱两可的函数名称不是有效的 C++,因此无法编译,所以在这里是安全的。

【讨论】:

  • 小错字:signals 定义为public(注意没有冒号)。因此,private signals: 实际上扩展为private public:,而不是private: public:
【解决方案2】:

看看qobjectdefs.h (QT5.0+)。其中定义了 moc 宏

#     define signals public

如您所见,信号头文件中使用的宏被定义为公共的。至于显式的 statet public,private,protected 指令,这些在信号部分被忽略。 QT 5.0 之前的版本将信号定义为受保护。这些仍然可用于使用SIGNAL() 宏进行连接。

插槽宏

#     define slots

被定义为空宏,因此可用于:

public slots:
private slots:
protected slots:

方法可见性用于直接方法调用,因此不能直接从外部类调用 private/protected。

使用connect 语句仍然独立于可见性工作。这是预期的行为,并在 moc 生成的代码中实现。

如果我没记错的话,在早期版本的 Qt 中,插槽也自动为 public,但我现在没有找到参考。

任何其他类都可以连接到来自外部类的信号,只要在类中给出 Q_OBJECT 宏并且外部类是已知的(包括标题)。由于信号是按类定义的,因此在不同的类中具有相同的信号是完全合法的。这也很方便,例如在所有类中都有一个信号 sendInfo(QString) 更容易记住。 Q_OBJECT 宏使 moc 创建将信号连接到插槽所需的代码,与可见性无关。

【讨论】:

  • 那一定已经改变了,因为我相信它曾经是define signals protected。所以这意味着可以从任何其他类发出信号。然而,奇怪的是为什么文档指出 private 插槽也可以从另一个类中调用。
  • 您可以通过连接从外部类调用私有插槽,这是真的,并且是通过 Q_OBJECT 宏和“moc”魔法实现的。但是声明为私有时不能直接调用槽。
  • 有趣,所以对于一个外来类到connect 的任何信号到另一个类的private slot 是否有效?所以private这个词只指正常的函数调用用例,而slot这个词表示函数在连接用例中总是public
  • 是的,您始终可以连接到来自外国课程的插槽。我们在我们的软件中也遇到过这种情况,我们也很惊讶,但这是信号槽连接的预期行为。
【解决方案3】:

发出的信号始终可供所有其他类使用,也就是说,任何其他类都可以始终连接到该信号(无论其发出信号的权限如何)。

在 Qt5 中,这不一定是真的。可以使用QPrivateSignal 作为信号的最后一个参数来定义信号,在这种情况下,只有声明信号的对象才能连接到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    • 2015-07-18
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多