108

假设我有这个信号:

signals:
    void progressNotification(int progress);

我最近才了解 Qt 中的 emit 关键字。到目前为止,我过去常常通过像普通函数一样调用它们来执行信号。所以而不是:

emit progressNotification(1000 * seconds);

我会写:

progressNotification(1000 * seconds);

像这样调用它们似乎有效,并且所有连接的插槽都会执行,那么使用 emit 关键字会导致不同的行为,还是只是语法糖?

4

3 回答 3

98

emit只是语法糖。如果您查看发出信号的函数的预处理输出,您会发现emit它已经消失了。

“魔术”发生在为信号发射函数生成的代码中,您可以通过检查 moc 生成的 C++ 代码来查看。

例如foo,一个没有参数的信号会生成这个成员函数:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

并且代码emit foo();被预处理为简单foo();

emitQt/qobjectdefs.h(无论如何以源代码的开源风格)定义,如下所示:

#ifndef QT_NO_EMIT
# define emit
#endif

(define guard 是为了让你可以通过no_keywordsQMake 配置选项将 Qt 与其他名称冲突的框架一起使用。)

于 2012-04-15T08:15:36.500 回答
5

18 个月后......我开始在@Mat 的回答下发表评论,并且很快就没有空间了。从而得到答案。

IMOemit既不是语法糖也不是简单的关键字,因为

  1. 它生成代码(如上面@Mat 所解释的),
  2. 它帮助connect机制认识到它确实是一个signal, 和
  3. 它使您的信号成为“更大”系统的一部分,其中信号和响应(插槽)可以同步或异步执行,或排队执行,具体取决于信号发出的位置和方式。这是信号/槽系统的一个非常有用的功能。

整个信号/槽系统与简单的函数调用不同。我相信它源于观察者模式。signala和 a之间还有一个主要区别slot不必实现信号,而必须实现插槽!

你走在街上,看到一所房子着火了(信号)。您拨打 911(将火警信号与 911 响应插槽连接)。信号只是发出的,而槽由消防部门实施的。可能不精确,但你明白了。让我们看一下OP的例子。

一些后端对象知道已经取得了多少进展。所以它可以简单地emit progressNotification(...)发出信号。由显示实际进度条的类来获取此信号并在其上执行。但是视图是如何连接到这个信号的呢?欢迎使用 Qt 的信号/槽系统。现在可以设想一个管理器类(通常是某种小部件),它由一个视图对象和一个数据计算对象(两者都是QObjects)组成,可以执行connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress)

让我们不要进入管理器类的设计方面,但只要说这就是信号/插槽系统的亮点就足够了。我可以专注于为我的应用程序设计一个非常干净的架构。并非总是如此,但很多时候,我发现我只是发出信号但实现了 slot

如果可以在不发出信号的情况下使用/调用信号方法,那么它必然意味着您从一开始就不需要将该函数作为信号

于 2017-01-07T22:52:11.420 回答
-4

第二个选项意味着您始终知道函数名称和函数参数是什么,并且您将其发送到的对象是该特定函数已知的。这两种情况并不总是正确的,所以这就是为什么要制作插槽和信号的两个主要原因。“幕后”的信号和槽机制只是一个表,其中包含指向连接的每个函数的指针。

此外,请查看此 pdf,它非常清楚地解释了信号和插槽机制的性质: http ://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

于 2012-04-15T08:13:50.730 回答