Declarar señal abstracta en clase de interfaz

¿Cómo declarar una señal Qt en una clase / interfaz abstracta cuando la clase implementadora ya está derivada de 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(); } 

    Como descubrí en los últimos días … la manera Qt de hacer esto es así:

     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(); } 

    Ahora puede conectarse a esas señales de interfaz.

    Si no tiene acceso a la implementación cuando se conecta a la señal, su statement de conexión requerirá un molde dynamic para QObject :

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

    ... y de esta manera no está obligado a exponer la clase de implementación a los suscriptores y clientes. ¡¡¡Sí!!!

    En Qt, “señales” es sinónimo de “protegido”. Pero ayuda a MOC a generar el código necesario. Entonces, si requiere una interfaz con algunas señales, debe declararlas como métodos protegidos abstractos virtuales. Todo el código necesario será generado por MOC; puede ver detalles, que “emitir una señal” se reemplazará con la llamada virtual del método protegido con el mismo nombre. Tenga en cuenta que el cuerpo del método aslo generado por Qt.

    ACTUALIZACIÓN: código de muestra:

    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() < < "on1"; } void MyListner::on2() { qDebug() << "on2"; } 

    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< QObject * >( i1 ), SIGNAL( event1() ), listner, SLOT( on1() ) ); QObject::connect( dynamic_cast< QObject * >( i2 ), SIGNAL( event2() ), listner, SLOT( on2() ) ); invoker->doWork(); return a.exec(); } 

    Hay dos problemas para declarar señales como métodos abstractos en las interfaces:

    1. Una señal es una señal del punto de vista de Qt solo cuando se implementa de una manera particular , es decir, cuando la implementación es generada por moc, y se incluye en los metadatos del objeto.

    2. Por lo general, es un mal diseño emitir señales directamente desde el exterior de un objeto.

    Como corolario, dado que la interfaz es abstracta, no es necesario que declare sus señales en absoluto; no tiene otra finalidad que documentar el bash, ya que:

    1. Si se implementa una señal en una clase que se deriva de la interfaz, puede usar el sistema de metaobjetos para verificar su presencia.

    2. Se supone que no debes llamar directamente a estos métodos de señal de todos modos.

    3. Una vez que transfiere dinámicamente la interfaz no objeto a QObject , ya no importa que la implementación se derive de la interfaz.

    Las únicas razones válidas para hacer tal gimnasia serían:

    1. Coaxial doxygen u otro generador de documentación para proporcionar documentación para su código.

    2. Fuerce a la clase concreta a tener una implementación de un método con el mismo nombre. Esto, por supuesto, no garantiza que sea, de hecho, una señal.