如何为 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";};
};
这有两个主要缺点:
- 由于构造函数,您的接口不再是真正的接口。
- 您的派生 类 不能从以这种方式设计的多个接口继承(钻石继承)。
我仍然需要尝试使用虚拟继承 (class InterfaceClass : public virtual QObject
) 看看是否可以在不引入其他问题的情况下解决 #2。
我想用 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";};
};
这有两个主要缺点:
- 由于构造函数,您的接口不再是真正的接口。
- 您的派生 类 不能从以这种方式设计的多个接口继承(钻石继承)。
我仍然需要尝试使用虚拟继承 (class InterfaceClass : public virtual QObject
) 看看是否可以在不引入其他问题的情况下解决 #2。