在接口类中声明抽象信号

当实现类已经从QObject / QWidget中被驱动出来时,如何在抽象类/接口中声明一个Qt信号?

class IEmitSomething { public: // this should be the signal known to others virtual void someThingHappened() = 0; } class ImplementEmitterOfSomething : public QWidget, public IEmitSomething { // signal implementation should be generated here signals: void someThingHappended(); } 

正如我在过去的几天里所发现的那样:Qt这样做的方式是这样的:

 class IEmitSomething { public: virtual ~IEmitSomething(){} // do not forget this signals: // <- ignored by moc and only serves as documentation aid // The code will work exactly the same if signals: is absent. virtual void someThingHappened() = 0; } Q_DECLARE_INTERFACE(IEmitSomething, "IEmitSomething") // define this out of namespace scope class ImplementEmitterOfSomething : public QWidget, public IEmitSomething { Q_OBJECT Q_INTERFACES(IEmitSomething) signals: void someThingHappended(); } 

现在你可以连接到这些接口信号。

如果连接到信号时无法访问实现,则连接语句将需要dynamic转换为QObject

 IEmitSomething* es = ... // your implementation class connect(dynamic_cast<QObject*>(es), SIGNAL(someThingHappended()), ...); 

…这样你就不必将实现类暴露给订阅者和客户端。 是啊!

在Qt中,“信号”是synonim的“保护”。 但是它有助于MOC生成必要的代码。 所以,如果你需要一些信号的接口 – 你应该声明它们是虚拟的抽象保护方法。 所有必要的代码将由MOC生成 – 您可能会看到详细信息,“发出somesignal”将被同名的受保护方法的虚拟调用replace。 请注意,与Qt生成的方法的主体。

更新:示例代码:

MyInterfaces.h

 #pragma once struct MyInterface1 { signals: virtual void event1() = 0; }; struct MyInterface2 { signals: virtual void event2() = 0; }; 

MyImpl.h

 #ifndef MYIMPL_H #define MYIMPL_H #include <QObject> #include "MyInterfaces.h" class MyImpl : public QObject , public MyInterface1 , public MyInterface2 { Q_OBJECT public: MyImpl( QObject *parent ); ~MyImpl(); void doWork(); signals: void event1(); void event2(); }; class MyListner : public QObject { Q_OBJECT public: MyListner( QObject *parent ); ~MyListner(); public slots: void on1(); void on2(); }; #endif // MYIMPL_H 

MyImpl.cpp

 #include "MyImpl.h" #include <QDebug> MyImpl::MyImpl(QObject *parent) : QObject(parent) {} MyImpl::~MyImpl() {} void MyImpl::doWork() { emit event1(); emit event2(); } MyListner::MyListner( QObject *parent ) {} MyListner::~MyListner() {} void MyListner::on1() { qDebug() << "on1"; } void MyListner::on2() { qDebug() << "on2"; } 

main.cpp中

 #include <QCoreApplication> #include "MyImpl.h" int main( int argc, char *argv[] ) { QCoreApplication a( argc, argv ); MyImpl *invoker = new MyImpl( NULL ); MyListner *listner = new MyListner( NULL ); MyInterface1 *i1 = invoker; MyInterface2 *i2 = invoker; // i1, i2 - not QObjects, but we are sure, that they will be. QObject::connect( dynamic_cast< QObject * >( i1 ), SIGNAL( event1() ), listner, SLOT( on1() ) ); QObject::connect( dynamic_cast< QObject * >( i2 ), SIGNAL( event2() ), listner, SLOT( on2() ) ); invoker->doWork(); return a.exec(); } 

在接口中将信号声明为抽象方法有两个问题:

  1. 一个信号是Qt的观点中的一个信号,只有这个信号是以特定的方式实现时,也就是说,当这个实现是由moc生成的,并且包含在这个对象的元数据中。

  2. 直接从物体外部发射信号通常是不好的devise。

作为推论,因为界面是抽象的,所以你根本不需要声明它的信号 – 除了logging意图之外,它没有任何用途,因为:

  1. 如果一个信号在从接口派生的类中实现,那么可以使用元对象系统来validation它的存在。

  2. 你不应该直接调用这些信号方法。

  3. 一旦你dynamic地将非对象接口转换为QObject ,那么实现是从接口派生出来的并不重要。

留下做这种体操的唯一有效的理由是:

  1. 同轴电缆doxygen或其他文档生成器为您的代码提供文档。

  2. 强制具体类具有相同名称的方法的实现。 这当然不能保证它实际上是一个信号。