【问题标题】:How to make Qt Signal emit by value without compile errors instead of reference?如何使 Qt Signal 按值发出而不是编译错误而不是引用?
【发布时间】:2018-11-22 12:32:54
【问题描述】:

我读到 qt 中的信号/槽概念应该始终按值而不是引用传递参数,以确保信号/槽在线程之间完美地工作。

我现在有一段代码,它只会在信号的参数通过引用而不是值发出时编译:

#include <QObject>

class mythirdclass {
public:
    mythirdclass();
};

class mysecondclass : public QObject, public mythirdclass {
public:
    mysecondclass(mythirdclass third);
};

class myclass : public QObject {
    Q_OBJECT
public:
    myclass();

signals:
    // not working
    void messageReceived(mysecondclass mymessage);
    // working
    // void messageReceived(mysecondclass &mymessage);
};

myclass::myclass()
{
    mythirdclass third;
    mysecondclass msg(third);
    emit messageReceived(msg);

}

mysecondclass::mysecondclass(mythirdclass third)
{
    // DO stuff
}

mythirdclass::mythirdclass()
{
}

编译错误是:

..\example\main.cpp: In constructor 'myclass::myclass()':
..\example\main.cpp:28:20: error: use of deleted function 'mysecondclass::mysecondclass(const mysecondclass&)'
  emit signal(second);
                    ^
..\example\main.cpp:8:7: note: 'mysecondclass::mysecondclass(const mysecondclass&)' is implicitly deleted because the default definition would be ill-formed:
 class mysecondclass : QObject, public mythirdclass {
       ^

基于我想为mysecondclass 编写一个复制构造函数的错误,但是经过一些尝试我现在​​放弃了,因为我没有做对。

所以我的问题是:

  • 为什么编译失败?
  • 如果由于缺少复制构造函数而失败,为什么编译器无法隐式定义?
  • 在我的例子中,工作拷贝构造函数会是什么样子?

提前致谢。

【问题讨论】:

  • 您的mysecondclass 不是有意继承public QObject...? ??????
  • 你说得对,忘记了。
  • 这是完整代码吗?
  • @JBL 这是一个最小的例子。真实世界的场景是myclass 是一个包装类,它与QCanBusDeviceQCanBusFrame 接口。 mythirdclassQCanBusFramemysecondclass 是我在应用层任何地方使用的特定消息类。

标签: c++ qt copy-constructor qt-signals


【解决方案1】:

为什么编译失败?

因为按值传递意味着复制,如果复制构造函数被删除,那么它根本无法按值传递,并且您的函数无法使用此签名进行编译,而它可以通过引用接收其参数,因为它没有t 涉及复制。

如果由于缺少复制构造函数而失败,为什么编译器无法隐式定义?

它实际上失败了,因为它无法隐式定义一个。原因是你的类派生自QObject。还有QObjectdoesn't have a public or protected copy-constructor,设计使然。所以编译器不能隐式定义一个。

在我的例子中,工作拷贝构造函数会是什么样子?

鉴于QObjects 的性质,以及当涉及QObjects 不可复制时其背后的设计决策,我建议不要使用采用QObjects 或从它派生的类的信号和插槽按值(或简单地执行此操作的任何函数,信号/插槽主要是深层函数),而是通过引用或指针。

【讨论】:

  • 感谢您的深入解释!只要我没有遇到任何与信号发射和多线程相关的问题,我都会参考。
【解决方案2】:

对于第三个问题,如果您不想为 mysecondclass 定义默认构造函数,您的复制构造函数可能看起来像

 mysecondclass(mysecondclass const &other) : mythirdclass() {
    /// stuff
 }

对于您的第二个问题,我想(不确定)默认复制构造函数尝试使用已自动删除的默认构造函数,因为您已经从 mythirdclass 的对象定义了 mysecondclass 的另一个构造函数(我建议您此处的参数使用 const 引用以避免无用的复制)

【讨论】:

  • 感谢有关const&amp; 的提示,我会将构造函数更改为mysecondclass::mysecondclass(const thirdclass &amp;third)。我还添加了一个默认构造函数,只是忘记了。但是,这样的mysecondclass::mysecondclass() 的存在不会改变编译错误。
猜你喜欢
  • 2014-08-04
  • 2012-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-04
相关资源
最近更新 更多