可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How to declare a Qt signal in an abstract class / interface when the implementing class is already derrived from QObject/QWidget?
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(); }
回答1:
As I found out in the last days... the Qt way of doing this is like this:
class IEmitSomething { public: virtual ~IEmitSomething(){} // do not forget this signals: //
Now you can connect to those interface signals.
If you don't have access to the implementation when connecting to the signal your connect statement will require a dynamic cast to QObject
:
IEmitSomething* es = ... // your implementation class connect(dynamic_cast(es), SIGNAL(someThingHappended()), ...);
... and this way you're not forced to expose the implementation class to subscribers and clients. Yeah!!!
回答2:
In Qt, "signals" is synonim for "protected". But it helps MOC to generate necessary code. So, if you require interface with some signals - you should declare them as virtual abstract protected methods. All neccessary code will be generated by MOC - you may see details, that "emit somesignal" will be replaced with virtual call of protected method with same name. Note, that the body of with method aslo generated by Qt.
UPDATE: Sample code:
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 #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 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()
main.cpp
#include #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( i1 ), SIGNAL( event1() ), listner, SLOT( on1() ) ); QObject::connect( dynamic_cast( i2 ), SIGNAL( event2() ), listner, SLOT( on2() ) ); invoker->doWork(); return a.exec(); }
回答3:
There are two problems with declaring signals as abstract methods in interfaces:
A signal is a signal from Qt's viewpoint only when implemented in a particular way - namely, when the implementation is generated by moc, and is included in the metadata for the object.
It is usually bad design to emit signals directly from the outside of an object.
As a corollary, since the interface is abstract, you don't really need to declare its signals at all - it serves no purpose other than for documenting the intent, since:
If a signal is implemented in a class that derives from the interface, you can use the metaobject system to verify its presence.
You're not supposed to directly call these signal methods anyway.
Once you dynamically cast the non-object interface to QObject
, it doesn't matter anymore that the implementation was deriving from the interface.
The only valid reasons left for doing such gymnastics would be to:
Coax doxygen or another documentation generator into providing documentation for your code.
Force the concrete class to have an implementation of a method with the same name. This doesn't of course guarantee that it is in fact a signal.