这里的C ++新手。我在读《信号和插槽的更深入的了解》,它声称1)回调本质上是类型不安全的,2)为了使它们安全,您需要在函数周围定义一个纯虚拟类包装器。我很难理解这是真的。例如,这是Qt在其教程页面上提供的信号和插槽代码:
// Header file
#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;
};
// .cpp file
void 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() == 12
b.setValue(48); // a.value() == 12, b.value() == 48
这是使用回调重写的代码:
#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);
如您所见,回调版本是类型安全的,并且比Qt版本短,尽管他们声称不是。除了,它没有定义任何新类Counter
。它仅使用标准库代码,不需要特殊的编译器(moc)即可工作。那么,为什么信号和插槽优先于回调呢?C ++ 11是否简单地淘汰了这些概念?
谢谢。
为什么信号和插槽比普通的旧回调更好?
因为信号很像普通的旧回调,所以除了具有额外的功能并与Qt API深度集成之外。它不是火箭科学-回调+附加功能+深度集成比单独的回调要强大。C ++可能最终会提供一种更干净的回调方法,但这并不能取代Qt信号和插槽,更不用说使它们过时了。
自从Qt 5以来,插槽方面就变得不那么重要了,它可以将信号连接到任何功能。但是,插槽仍与Qt元系统集成,许多Qt API使用该系统来使工作正常进行。
是的,您几乎可以使用回调来实现信号应该实现的所有功能。但这并不容易,它有点冗长,它不会自动处理排队的连接,它不会像信号那样与Qt集成,您可能也可以解决它,但是它将变得更加冗长。
对于QML来说,Qt是当今的主要关注点,但实际上您对Qt的信号感到困惑。因此,我认为信号会持续存在。
信号和插槽“更好”,因为Qt在概念上围绕它们而构建,它们是API的一部分,并且被许多API使用。这些概念已经存在于Qt中很长时间了,从C ++过去,它除了提供从C继承来的简单的旧函数指针外,没有提供太多的回调支持。这也是Qt不能简单地切换到std回调的原因-它会打破很多东西,这是不必要的努力。同样的原因,Qt继续使用那些邪恶的,不安全的普通旧指针而不是智能指针。信号和插槽并不是一个过时的概念,在使用Qt时,从技术上讲也是如此。C ++太晚了。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句