如何为 QObject 创建接口 class

How create Interface for QObject class

我想用 signal/slot 系统为 QObject class 创建一个界面。

下面的代码有效但有一个缺点:接口继承 QObject 并且没有 Q_OBJECT 宏。

我想做一个纯虚接口,所以InterfaceClass不应该有构造函数。但是在 RealisationClass 中我不能调用 QObject (错误:类型 'QObject' 不是 'RealisationClass' 的直接基础)或者 InterfaceClass (它没有构造函数 InterfaceClass(QObject* parent)) 构造函数。此外,我无法在 InterfaceClass 中添加 Q_OBJECT 宏(错误:对 InterfaceClass 的 'vtable' 的未定义引用)

那么,我应该如何更改 classes 以在 RealisationClass 中添加 QObject() 构造函数并添加 Q_OBJECT 宏(或删除 QObject 继承)接口类。

IntefaceClass.h:

#ifndef INTERFACE_CLASS_H
#define INTERFACE_CLASS_H
#include <QObject>

class InterfaceClass : public QObject {
    Q_OBJECT
 public:
  virtual ~InterfaceClass(){};
  virtual void foo() = 0;
};
Q_DECLARE_INTERFACE(InterfaceClass, "Interface")
#endif // INTERFACE_CLASS_H

RealisationClass.h:

#include <QObject>
#include <QDebug>

#include "InterfaceClass.h"

class RealisationClass : public InterfaceClass {
  Q_OBJECT
  Q_INTERFACES(InterfaceClass)
 public:
    explicit RealisationClass(QObject* parent = nullptr){};
    void foo() override {qDebug() << "Hello, world";};
};

main.cpp:

#include <QCoreApplication>

#include "RealisationClass.h"
#include "InterfaceClass.h"
#include <QObject>
#include <QTimer>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QTimer everySecondTimer;
    everySecondTimer.setInterval(1000);
    QScopedPointer<InterfaceClass> interfacePointer(new RealisationClass);
    QObject::connect(&everySecondTimer, &QTimer::timeout, interfacePointer.get(), &InterfaceClass::foo);
    everySecondTimer.start();
    return a.exec();
}

编辑

Q_OBJECT宏问题还有一个原因:我没有将InterfaceClass.h作为目标添加到Cmake的AUTOMOC(qmake(moc)没有处理这个文件)。

使用具有 QObject 层次结构的界面真的很痛苦。您通常希望您的接口具有 QObject 的一些特性(即 signals/slots、销毁信号、与 Qt API 集成),但它是一个轻量级的接口定义。除非对 Qt 进行重构,以便存在在整个 Qt 代码库中使用的 IQObject,否则您无法获得完美的解决方案。我推荐的是简单地将所有构造函数调用转发到 QObject:

#ifndef INTERFACE_CLASS_H
#define INTERFACE_CLASS_H
#include <QObject>

class InterfaceClass : public QObject {
    Q_OBJECT
 public:
  using QObject::QObject; // <<--------

  virtual ~InterfaceClass(){};
  virtual void foo() = 0;
};
Q_DECLARE_INTERFACE(InterfaceClass, "Interface")
#endif // INTERFACE_CLASS_H

using QObject::QObject 行中,InterfaceClass 现在具有与 QObject 相同声明的构造函数。他们所做的只是将呼叫转发给 QObject。这样,您现在可以在 RealisationClass:

中执行此操作
#include <QObject>
#include <QDebug>

#include "InterfaceClass.h"

class RealisationClass : public InterfaceClass {
  Q_OBJECT
  Q_INTERFACES(InterfaceClass)
 public:
    explicit RealisationClass(QObject* parent = nullptr)
      : InterfaceClass(parent) // <<------
    {};
    void foo() override {qDebug() << "Hello, world";};
};

这有两个主要缺点:

  1. 由于构造函数,您的接口不再是真正的接口。
  2. 您的派生 类 不能从以这种方式设计的多个接口继承(钻石继承)。

我仍然需要尝试使用虚拟继承 (class InterfaceClass : public virtual QObject) 看看是否可以在不引入其他问题的情况下解决 #2。