【问题标题】:Subclassing template class and connect to signal子类化模板类并连接到信号
【发布时间】:2017-08-08 00:37:35
【问题描述】:

我正在尝试继承 QQueue 以添加一些功能。 实际上,我无法进行子类化,但因为代码很短,我重写了自己的实现:

#ifndef MYQUEUE_H
#define MYQUEUE_H

#include <QObject>
#include <QtCore/qlist.h>

QT_BEGIN_NAMESPACE

template <class T>
class MyQueue : public QList<T>
{
Q_OBJECT

public:
    // compiler-generated special member functions are fine!
    inline void swap(MyQueue<T> &other) Q_DECL_NOTHROW { QList<T>::swap(other); } // prevent QList<->QQueue swaps
#ifndef Q_QDOC
    // bring in QList::swap(int, int). We cannot say using QList<T>::swap,
    // because we don't want to make swap(QList&) available.
    inline void swap(int i, int j) { QList<T>::swap(i, j); }
#endif
    inline void enqueue(const T &t) { QList<T>::append(t); emit enqueued(); }
    inline T dequeue() { return QList<T>::takeFirst(); }
    inline T &head() { return QList<T>::first(); }
    inline const T &head() const { return QList<T>::first(); }

signals:
    void enqueued();
};

QT_END_NAMESPACE

#endif // MYQUEUE_H

基本上,只要有东西入队,它就会发出一个信号。 我不知道将该信号绑定到插槽的正确语法:

MyQueue<QString> queue;
connect(&queue, &MyQueue::enqueued, this, &MainWindow::process_queue);

错误:“模板类 MyQueue”未使用模板参数 连接(&queue, &MyQueue::enqueued, 这个, &MainWindow::process_queue); ^

它说我正在使用MyQueue(即模板类)而没有指定模板参数(QString)。

我试图添加它,但我做错了:

connect(&queue, &MyQueue<QString>::enqueued, this, &MainWindow::process_queue);

错误:没有匹配函数调用 'MainWindow::connect(MyQueue, void (MyQueue::)(), MainWindow*, void (MainWindow::*)())'

连接此类信号的正确语法是什么?

【问题讨论】:

  • 我认为你的方法行不通。除了模板类,如果你想使用信号/槽,你必须将它们与QObjects 或其子类一起使用。
  • 为什么MyQueue不能继承非模板基类,把需要的signal放到基类中?
  • 您的意思是一种添加所需信号的包装器吗?这可能是一个可以接受的解决方法。

标签: c++ qt templates


【解决方案1】:

使用 moc 进行信号和插槽连接;不支持模板。如果您对基本原理感兴趣,可以在此处阅读有关此决定的更多信息:http://doc.qt.io/qt-5/why-moc.html

也就是说,您在示例中显示的所有功能都可以在 QStringList 中使用,因此您可以在此实例中将其视为一个选项。

【讨论】:

  • 太可惜了! QString 只是一个例子,我有一个自定义类型的队列。我希望在队列更改(入队、出队等)时收到通知
  • @Mark 除了将信号连接到MyQueue 之外,您能否将其连接到入队和出队的点?这似乎是更习惯的方式。
  • 因为这可能发生在代码的几个部分,我会避免在这里和那里重复相同的sn-p。
  • @Mark 我认为您在 Qt 框架中提供的选项我看到了 3 个选项,从最好到最差列出:1)从所有入队和出队位置添加信号 2)使用一个非模板化的容器 3) 创建一个非模板化的接口,可以用来发送信号。
【解决方案2】:

根据我的评论...您可能有 MyQueue 从具有所需信号的合适基类继承。

class MyQueueBase: public QObject {
  Q_OBJECT;
public:
  virtual ~MyQueueBase ()
    {}
signals:
  void enqueued();
};

那么MyQueue就变成了……

template<class T>
class MyQueue: public MyQueueBase,
               public QList<T>
{
public:

  /*
   * All as before but without the signal declaration.
   */
};

使用上面的代码可以连接到基类或派生类...

connect(&queue, &MyQueueBase::enqueued, this, &MainWindow::process_queue);
connect(&queue, &MyQueue<QString>::enqueued, this, &MainWindow::process_queue);

【讨论】:

  • 我不是这个解决方案的忠实拥护者,因为需要额外的工作,并且增加了间接/维护层。但如果我说实话,我之前使用过这个解决方案,而其他解决方法更令人讨厌。所以我不情愿地给这个+1,因为即使它是最后的手段,在某些情况下它是最好的解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 2021-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多