2016-03-08 94 views
7

在我一年的Qt编程中,我学到了很多关于信号和插槽的知识。但还不够......公共功能与公共时隙

http://doc.qt.io/qt-5/signalsandslots.html

插槽可用于接收信号,但他们也都正常 成员函数。

所以......有什么理由不申报的每一个功能,从QObject继承,作为一个槽,它是否需要是一个或不是一类?

在上面的链接,他们举一个例子:

小基于QObject的级可能​​是:

#include <QObject> 

class Counter : public QObject 
{ 
    Q_OBJECT 

public: 
    Counter() { m_value = 0; } 

    int value() const { return m_value; } 

public slots: 
    void setValue(int value); 

signals: 
    void valueChanged(int newValue); 

private: 
    int m_value; 
}; 

为什么定义value()功能作为一个普通的函数,而不是一个插槽?如果他们确实把它作为一个插槽,会有什么负面结果吗?

回答

12

回到过去,如果你想连接信号,你别无选择,只能使用插槽。在Qt 5中不再是这种情况,可以连接到常规成员函数甚至自由函数或lambda表达式。

声明一个槽将那个函数注册到该特定对象的元数据中,使得它可以被所有依赖元对象的Qt功能所使用。除此之外,它是文档所述的常规成员函数。槽功能本身没有什么特别之处,不同之处在于在元对象中为它生成元数据。

这意味着在编译时间和可执行文件大小方面,声明插槽都需要花费一定的代价,尽管很小。我认为把所有的公共职能作为插槽是矫枉过正的。只有在实际需要插槽时才使用插槽,如果它不能与常规功能一起工作,使其成为插槽,效率会更高。

此外,请注意几乎在所有情况下,信号都使用返回类型void进行声明。这与信号的典型使用情况有关 - 它们通常可以传递参数,但很少返回任何信息。尽管可以通过连接到插槽的信号返回值,但这种情况极少发生。因此,声明一个返回某个要插入的插槽的函数并没有多大意义,因为它返回一个值意味着它很可能不会在典型的信号/插槽上下文中使用。这就是为什么在这个例子中getter不是插槽。作为插槽的setter在Qt 5中是多余的,并且可能是此示例代码的产品,可追溯到Qt 4.

最后,从常规公共职能中分离插槽是说明意图的好方法,或“API “如果你愿意的话。例如,我在扩展QML时主要使用插槽,因此我不必将每个函数明确标记为invokeable - 与上一段中提到的场景不同,这些插槽通常会返回内容,但它们并不真正用于连接。这样我就清楚地了解了该类所提供的接口的设计。

-1

对于某些功能,您需要一个返回值。这不会在插槽中轻松工作。在槽中,你不能使用函数的返回值或给它们一个参考参数。是的,你可以做到这一点,但你有一个时间问题。 无论您是在软件架构上使用插槽还是正常的成员函数依赖项,

另外,插槽在事件循环中运行。如果这是有意或无意的,它取决于你的代码。

+1

这个答案没有丝毫意义,甚至没有解决这个问题。 – MrEricSir

+0

您可以在插槽中使用返回值吗?或者甚至以正确的方式获取参考参数的值? – SuperFliege

+1

@SuperFliege - 插槽只是一个函数,它的功能与函数完全相同。多线程和对象生命周期是完全不同的问题,并影响正常功能,就像它们影响插槽一样。 – dtech

2

除了ddriver的回答,这是最好的/正确的答案(在那里+1),我还会争辩说定义所有成员函数为公开槽是混淆的。他们定义功能(私人/公共/插槽等)的方式会影响班级的感知使用。

我的意思是......你可以说所有的功能都应该是公开的(或公开的插槽),然后涵盖所有的情况。然而,这可能会让您班级的未来用户感到困惑。考虑到int value()是一个公共插槽(它不是最好的例子),有人可以尝试使用它作为一个,但函数本身具有返回值,这对于插槽来说并不合适。它对于一个正常的成员函数来说是有意义的,在该函数中可以访问返回值(作为正常函数调用)。

要遵循的一条规则是始终保持您的函数和变量为局部作用域和私有角色(默认情况下),并且只为其他用途(public-ness,slots,global等)打开它们。 )当你真的需要他们。这使您的类界面更容易理解,并避免以后用户感到困惑。

我肯定是这个规则的拇指的名称,所以你可以看看它的一些编码技术的网站,但我不记得它:(

编辑

另一个小例子是自动完成...如果你所有的功能都是插槽,那么当你正在做你的自动完成选项的列表可能会很长并且不清楚是什么。如果你只有几个特定的​​成员是插槽那么它更容易知道选哪个。

+1

您正在寻找的术语是封装。 – thuga

+0

@thuga - 是封装绝对是主题......但我确定有一些“规则名称”用于保持一切最小范围....也许它只是“封装规则”?:o谢谢:) –

+0

我唯一要添加到这个答案的是公共插槽是Q_INVOKABLE,并且您可能不希望所有公共方法都可以从QML上下文访问。 – MrEricSir

2

在参考enca从code_fodder的答案来看,应该指出的是,真的没有私人插槽这样的东西。

例如:

class MyClass : public QObject 
{ 
    Q_OBJECT 
public: 
    MyClass() 
     :QObject(NULL) {} 

private slots: 
    void Hello() { qDebug("Hello World\n"); } 
}; 

#include "main.moc" 

int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 

    MyClass* cls = new MyClass; 
    QMetaObject::invokeMethod(cls, "Hello"); 

    return a.exec(); 
} 

正如我们所看到的,调用该函数Hello是从类的外部成功。

+0

它也适用于连接吗?顺便说一句,调用私有函数的可能性完全在Qt上,没有访问检查。私人插槽是非常真实的,即使不被meta系统所尊重:) – dtech

+0

是的,如果你通过旧的连接方法(pre Qt 5)连接,使用SIGNAL,SLOT宏。例如用QTimer *连接(pTimer,SIGNAL(timeout()),cls,SLOT(Hello())); * – TheDarkKnight

+1

@TheDarkKnight它是一个非常有趣的观察(+1分享)。当我在同一个班级建立内部连接时,我总是使用私人插槽,否则......但我从来没有想过要检查(或注意)Qt不会妨碍私人插槽的可见性! - 仍然,这不会改变我定义它们的方式,因为即使Qt是宽松的(或只是错误在这里)我不喜欢:) –

0

您不希望所有方法都是插槽的另一个用例是,您将对象通过Qt's WebKit Bridge公开时段: 可通过JavaScript调用所有公用插槽。

所以如果你想要一个不能从JavaScript调用的公共方法,你不能声明它是一个插槽。

+0

我的问题的主要原因是因为我必须向JavaScript公开对象 - 并且使用应用程序特定方面的人员非常高兴地要求几乎每个函数都可以成为一个插槽。我想限制这个......但我需要一个原因。对于返回值的函数,这些函数可以通过使它们成为'Q_PROPERTY'来成为JavaScript的可调参数。 – Thalia