QT中的信号-槽比我们常用的callback到底牛在哪里?

来源:互联网 发布:牙膏选择 知乎 编辑:程序博客网 时间:2024/04/29 19:45

这里写图片描述

刚刚接触qt, 发现有一个东西叫signal slot ,翻译为信号槽。

免责声明,我是一个beginner。Google了很多资料,很多文章写signal slot的。所以,这里只是把我个人觉得精彩的地方整理在一起,再偶尔加上一点点自己的看法而已。

看问题,再stackoverflow上看到这样一个提问,大意思是这样:
他们团队的qt项目中,一位资深的软件工程师运用了大量的c-style的回调函数,而没用使用qt中很精妙的signal slot机制。

回调有哪些缺点?
Callbacks have two fundamental flaws: Firstly, they are not type-safe. We can never be certain that the processing function will call the callback with the correct arguments. Secondly, the callback is strongly coupled to the processing function since the processing function must know which callback to call.

什么叫类型安全?
类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域。“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制;有的时候也用“类型安全”形容某个程序,判别的标准在于该程序是否隐含类型错误。类型安全的编程语言与类型安全的程序之间,没有必然联系。好的程序员可以使用类型不那么安全的语言写出类型相当安全的程序,相反的,差一点儿的程序员可能使用类型相当安全的语言写出类型不太安全的程序。绝对类型安全的编程语言暂时还没有。

什么是信号、槽?
A signal is an observable event, or at least notification that the
event happened.
A slot is a potential observer, typically in the form a function to be
called.
You connect a signal to a slot to establish the observableobserver
relationship.

信号槽有啥缺点呢?
Compared to callbacks, signals and slots are slightly slower because of the increased flexibility they provide, although the difference for real applications is insignificant.
In general, emitting a signal that is connected to some slots, is approximately ten times slower than calling the receivers directly, with non-virtual function calls.
This is the overhead required to locate the connection object, to safely iterate over all connections (i.e. checking that subsequent receivers have not been destroyed during the emission), and to marshall any parameters in a generic fashion. While ten non-virtual function calls may sound like a lot, it’s much less overhead than any new or delete operation, for example. As soon as you perform a string, vector or list operation that behind the scene requires new or delete, the signals and slots overhead is only responsible for a very small proportion of the complete function call costs. The same is true whenever you do a system call in a slot; or indirectly call more than ten functions. The simplicity and flexibility of the signals and slots mechanism is well worth the overhead, which your users won’t even notice.

官方出品(节选)

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt’s widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal. Qt’s widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are interested in.

简单的例子:

/ Header file#include <QObject>class Counter : public QObject{    Q_OBJECTpublic:    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;};// .cpp filevoid Counter::setValue(int value){    if (value != m_value) {        m_value = value;        emit valueChanged(value);    }}// Later on...Counter a, b;QObject::connect(&a, SIGNAL(valueChanged(int)),                 &b, SLOT(setValue(int)));a.setValue(12);     // a.value() == 12, b.value() == 12b.setValue(48);     // a.value() == 12, b.value() == 48

Here is that code rewritten using callbacks:

#include <functional>#include <vector>class Counter{public:    Counter() { m_value = 0; }    int value() const { return m_value; }    std::vector<std::function<void(int)>> valueChanged;    void setValue(int value);private:    int m_value;};void Counter::setValue(int value){    if (value != m_value) {        m_value = value;        for (auto func : valueChanged) {            func(value);        }    }}// Later on...Counter a, b;auto lambda = [&](int value) { b.setValue(value); };a.valueChanged.push_back(lambda);a.setValue(12);b.setValue(48);
1 0
原创粉丝点击