信号/槽与直接函数调用

7

我开始学习Qt 4.5,并发现信号/槽机制很有帮助。然而,现在我发现自己正在考虑两种类型的架构。

这是我将要使用的一种。

class IDataBlock
{
   public:
   virtual void updateBlock(std::string& someData) = 0;
}

class Updater
{

   private:
    void updateData(IDataBlock &someblock)
    {
         ....
       someblock.updateBlock(data);
          ....
    }
}

注意:为了简洁起见,代码已内嵌。
现在使用信号(signal)我可以:
void Updater::updateData()
{
    ...
    emit updatedData(data);
}

这种写法更简洁,减少了接口的需求,但我仅仅因为能做到就应该这么做吗?第一个代码块需要更多的打字和更多的类,但它展示了一种关系。第二个代码块中,所有的东西都更加“无形”。哪一种更加理想,如果是逐案而定的话,有哪些指导方针呢?

3个回答

10

发送信号只需要少量的开关和一些额外的函数调用(取决于连接的内容和方式),但开销应该是最小的。

信号的提供者无法控制其客户端是谁,甚至在emit返回时,它们是否实际上都接收到了信号。

这非常方便,可以完全解耦,但在执行顺序很重要或者想要返回某些东西时可能会导致问题。

永远不要传递指向临时数据的指针(除非你确切知道你在做什么,即使是这样也要小心)。如果必须这样做,请传递您成员变量的地址 - Qt 提供了一种延迟对象销毁的方法,直到处理完所有事件为止。

信号也可能需要事件循环运行(除非连接是直接的,我认为)。

总的来说,在事件驱动的应用程序中使用它们非常有意义(如果没有它们,实际上会很快变得非常烦人)。

如果您已经在项目中使用Qt,请务必使用它们。如果对Qt的依赖性不可接受,则boost具有类似的机制。


3
另外还有一个区别:#1 与 IDataBlock 接口紧密耦合,Updater 类需要知道 "someblock"。#2 可以通过连接调用(或多个连接和断开连接)进行后期耦合,这导致了更加动态的方法。#2 的行为类似于消息(想想 Smalltalk/ObjC),而不是调用(想想 C/C++)。消息也可能受到多重分派的影响,在 #1 中需要手动实现该功能。
我更喜欢使用信号/槽,因为它们具有灵活性,除非代码性能或立即返回数据的需求不允许(或者不希望依赖于 Qt)。

2
这两种形式看起来可能相似,从功能上来说确实如此。但在实践中,你正在解决一个更大的问题。在这些情况下,外部环境将导致这两个解决方案不等效。
一个常见的情况是确定源和汇之间的关系。它们是否互相了解?在你的第一个示例中,updateData() 需要传入 sink。但如果触发器是 GUI 按钮 [更新数据] 呢?按钮是通用组件,不应该知道 IDataBlock。
一种解决方法当然是向 Updater 添加一个 m_someblock 成员。现在,按钮会更新 Updater 中的任何成员。但这真的是你想要的吗?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接