关于c ++:什么是信号和插槽?

What are signals and slots?

有人能用简单的术语解释"信号和插槽"模式吗?


信号和插槽是一种将发送器(信号)和零个或多个接收器(插槽)分离的方法。假设您有一个系统,其中包含您希望向系统中对这些事件感兴趣的任何其他部分提供的事件。与其将生成事件的代码硬连接到想要了解这些事件的代码,不如使用信号和槽模式。

当发送方发出一个事件信号(通常通过调用与该事件/信号相关联的函数)时,该事件的所有接收器都会被自动调用。这允许您在程序生命周期内根据需要连接和断开接收器。

因为这个问题被标记为C++,所以这里有一个到BooSo.Studio库的链接,它有更彻底的解释。


我认为,当您将信号和插槽视为观察者模式或发布/订阅者模式的可能实现工具时,可以最好地描述它们。有一个signal,例如出版者端的buttonPressed(IdType)。每当按下按钮,所有连接到该信号的插槽都会被调用。插槽在用户端。例如,槽可以是sendMail(IdType)

随着事件"按钮按下",插槽将知道哪个按钮被按下,因为ID将被移交。IdType表示通过发布服务器和订阅服务器之间的连接发送的数据类型。用户可能进行的操作是connect(signal, slot),它可以将buttonPressed(IdType)sendMail(IdType)连接起来,这样,如果按下按钮,就会调用特定的插槽。

这方面的好处是用户(槽端)不需要关心信号的细节。它只需要连接。因此,这里有大量的松耦合。您可以更改按钮实现,但是插槽的接口仍然是相同的。

查看qt信号/插槽或增压信号了解更多信息。


想象一下在应用程序中有一个GUI。大多数情况下,控制流不会是非常线性的,也就是说,如果没有一个清晰的操作序列,那么用户就可以与图形用户界面(如按钮、菜单等)进行交互。

这本质上是一个事件驱动的模型,可以很好地用信号和槽模式实现。信号是由对象(比如图形用户界面组件)生成的事件,插槽是这些事件的接收器。

下面是一个例子:假设您有一个复选框,在您的编程语言中表示为一个对象。该复选框可以发生多种情况:它可以被切换,这也意味着它可以被设置或取消设置。这些是它能发出的信号。我们将它们命名为checkboxToggled、checkboxSet和checkboxUnset。如您所见,在本例中,复选框在切换时始终会发出复选框切换信号,但根据状态的变化情况,也会恰好发出另外两个信号中的一个。

现在想象一下还有一些其他的对象,也就是标签,为了这个例子,标签总是作为一个对象存在,但是可以"出现"和"消失",并且系统会发出哔哔声(也可以用一个对象表示),这只会发出哔哔声。那些是那些物体的狭槽。我们将它们称为"messageappear"、"message消失"和"哔"声。

假设您希望每次切换复选框时系统发出哔哔声,标签显示或消失取决于用户是否选中或清除了该复选框。

因此,您将以下信号连接到以下插槽(左侧的信号,右侧的插槽):

1
2
3
checkboxToggled -> beep
checkboxSet -> messageAppear
checkboxUnset -> messageDisappear

基本上就是这样。

信号和插槽也可能有参数。例如,使用设置数值的滑块,您希望在用户移动滑块后立即发送更改的值和发出的信号:sliderChanged(int)。

当然,要真正做一些有用的事情,您需要编写一些自己的类,其中包含一些自己的信号和槽。这是很容易做到的,并且使用这些自己的信号和插槽,您有一个以事件驱动方式与GUI或代码的其他部分交互的好方法。

请记住,信号和插槽通常是对称的,因为通常可能存在与插槽对应的信号。例如,复选框在切换时可能发出信号,但也可能包含一个用于切换复选框本身的槽。很容易实现分离复选框,这些复选框总是彼此相对设置。


我假设你在谈论qt的信号和时隙。很简单。

一个类的一个实例可以触发一个信号,而另一个类的另一个实例可以在一个槽中捕获该信号。有点像函数调用,只是调用函数的人不需要知道谁想要接收调用。

最好的说明方法是举个例子。类qpushButton具有信号qpushButton::Clicked()。只要点击按钮,就会触发该信号。按钮不需要知道谁对点击感兴趣。它只是发出信号,任何感兴趣的人都可以连接到它。按钮所在的Qdialog实际上是想知道何时单击按钮。它具有插槽myDialog::ButtonClicked()。在MyDialog中,您需要将buttons click()信号连接到对话框的buttonchecked()插槽,以便在触发信号时调用插槽。

一堆更先进的东西:

  • 参数,信号可以有参数,这些参数也可以选择性地传递到槽中。
  • 跨线程调用-如果您正在进行一个需要跨线程的信号槽连接,那么qt将自动缓冲信号并将其排队到正确的线程。例如,当GUI线程需要与工作线程通信时,这种情况会自动发生。

以下是Qt文档中的更多信息。


我为信号和插槽找到的最好的例子和解释是这篇代码项目文章。


有一种常见的误解,即类是人、狗、自行车等名词。那么认为一个人(例如)有狗和自行车是有道理的。

让我们从对象(应该是什么)开始。对象是数据和过程。什么是程序?数据和程序。对象应该是(相对而言)"小"的独立子程序。因为OO编程的教学非常模糊和误用(需要引用),人们认为所有的东西都需要是一个类或一个对象。但事实并非如此,对象是带有"small"API(公共子例程)的"small"独立程序。有些程序员甚至不把他们的项目分解成子程序,只使用数据和过程更适合的对象。

现在,假设我们同意对象是程序,我们可能同意在大多数情况下,程序不需要具有类似大小和复杂度的其他程序的副本(即一个对象不是指向另一个对象的指针),它可能需要较小的程序来管理数据(如数据结构),但imho不需要另一个对象。

为什么?因为耦合对象使它们相互依赖。为什么不好?因为当对象是独立的时,你可以测试它们,也可以向其他程序员和客户承诺对象(一个小的独立程序)能够高度确定地执行某些任务。您还可以确保只要没有对该对象进行任何更改,它就会继续执行。

那么插槽和信号是什么呢?如果您理解对象就像程序,并且理想情况下,它们不应该保存到其他对象的副本或指针,而您需要某种方式让它们进行通信。例如,在计算机上运行的进程可以使用套接字、IP地址和端口进行通信。对象可以使用与rpc非常相似的信号和插槽。这些是一种数据结构,用作存储对象的子例程(slots和允许其他对象调用(signal这些子例程(slots的适当参数)的两个较大对象之间的中介,而不知道这些其他对象需要哪些参数。

因此,底层结构是(可能)强类型过程指针的集合(可能是数组),其他对象可以使用适当的参数调用这些对象,而不需要指向这些对象的指针。调用者只需要访问定义预期参数的信号对象(不包含实现细节)。

这也很灵活,因为它允许一些特殊的用例,比如只响应一次信号的插槽,一个信号的多个插槽,以及其他类似的用例,比如去块。