You cannot define signals and slots in interfaces, as you would have to subclass QObject, which will result in a non-abstract class. In addition, once your interface dervies from QObject, all classes implementing this interface derive from QObject as well, which means you cannot subclass from other QObject subclasses (like QWidget), as QObject does not support multiple inheritance (this is the problem you are currently running into).
The (or one) solution is to define signals and slots in the interface, but not to subclass QObject. This does not strictily enforce the implementation of those signals and slots in interface implementations at compile time, but it enforces the implementation of the (ordinary) methods and clearly states that they have to be signals and slots in interface implementations. Signals and slots are resolved during runtime and as long as interface implementations subclass any QObject subclass they can be used.
@
class SampleInterface
{
// Delcaring those methods as signals and slots does NOT enforce
// that they are actually implemented as signals and slots in interface
// implentations, but it forces at least an implementation of ordinary
// methods and indicates clearly that those methods should be
// implemented as signals and slots. QMetaObject (or connect()) can
// be used to check if they have been actually implemented as signals
// and slots during runtime.
signals:
virtual void sampleSignal() = 0;
public slots:
virtual void sampleSlot() = 0;
};
Q_DECLARE_INTERFACE(SampleInterface, "SampleInterface")
class SampleQObjectImplementation : public QObject, SampleInterface
{
Q_OBJECT
Q_INTERFACES(SampleInterface)
signals:
void sampleSignal();
public slots:
void sampleSlot() { qDebug(Q_FUNC_INFO); emit sampleSignal(); }
};
Q_EXPORT_PLUGIN2(sampleQObjectImplementation , SampleQObjectImplementation)
class SampleQWidgetImplementation : public QWidget, SampleInterface
{
Q_OBJECT
Q_INTERFACES(SampleInterface)
signals:
void sampleSignal();
public slots:
void sampleSlot() { qDebug(Q_FUNC_INFO); emit sampleSignal(); }
};
Q_EXPORT_PLUGIN2(sampleQWidgetImplementation , SampleQWidgetImplementation)
// Connect to slots and signals using QObject as base class pointer
// (as returned by QPluginLoader::instance())
QObject* sampleQObjectImplementation = new SampleQObjectImplementation;
QObject* sampleQWidgetImplementation = new SampleQWidgetImplementation;
QObject::connect(sampleQObjectImplementation, SIGNAL(sampleSignal()),
sampleQWidgetImplementation, SIGNAL(sampleSlot()));
// Cast to SampleInterface to call methods directly
SampleInterface sampleInterface = qobject_cast<SampleInterface>(sampleQObjectImplementation);
sampleInterface->sampleSlot();
@
Brain to terminal. Not tested. Exemplary.
A variation to this idiom is to add a <code>QObject *object() { return this; }</code> method to the interface, which allows for using signals and slots with an interface pointer as well.
@
SampleInterface sampleQObjectInterface = qobject_cast<SampleInterface>(sampleQObjectImplementation);
SampleInterface sampleQWidgetInterface = qobject_cast<SampleInterface>(sampleQWidgetImplementation);
connect(sampleQObjectInterface->object(), SIGNAL(sampleSignal()),
sampleQWidgetInterface->object(), SLOT(sampleSlot()));
@
Brain to terminal. Not tested. Exemplary.