0

Suppose I have the following toy interface:

class iTest{
  virtual ~iTest(void) = 0;
  virtual void doA(void) = 0;
  virtual void doB(void) = 0;
}

Q_DECLARE_INTERFACE(iTest, "somestring")

I'd like to implement this in two classes: Base and Derived.

class Base : public QObject, public iTest
{
  Q_OBJECT
  Q_PLUGIN_METADATA (IID "somestring")
  Q_INTERFACES(iTEST)
  explicit Base(QObject* parent=0);
  void doA(void); // do common thing all derived need do
  int data; // some data member all derived should have
}

class Derived: public Base
{
  Q_OBJECT
  Q_PLUGIN_METADATA (IID "somestring")
  Q_INTERFACES(iTEST)
  explicit Derived(QObject* parent = 0);
  void doB(); // do something custom dervived objects need do
}

My faulty reasoning tells me that this should work. An abstract base class for the plugin giving functionality for a part of the interface while the derived classes constitute the remainder of it. I can get this to compile, with some judicious removal of macros (the base class metadata macro). However, the plugins resulting won't load. So I assume there's something faulty in my reasoning which a more experience Qt developer or c++ developer could point out that I just can't see.

  • All these `Q_` macro are processed by MOC compiler and bind some functionality to one instance of C++ object. And we have both `Base` and `Derived` "competing" for the same implicit functionality tied to one instance. I would not do such Qt class design then. I would rather expose plug-interface from the target class once but we can as many children of iTest as we want. And we can have many target plug-ins, why not. This is not a final answer and I myself would like to listen to the wise on that. – Alexander V Jul 25 '18 at 23:10

1 Answers1

1

I believe I've come up with a solution for this. As Alexander V mentioned above, the Q_ macros in the Base and Derived classes were conflicting with one another. The documentation states that only a single called to the Q_PLUGIN_METADATA macro can be in the code. What occurred to me is that the base class itself need not even be a Q_Object, it's just a container for functions. I, therefore, re-declared the classes as follows:

class Base: public iTest{
  void doA(void); // do something all derived should do
  int data; // data all derived should have
}

class Derived: public QObject, public Base{
  Q_OBJECT
  Q_PLUGIN_METADATA (IID "somestring")
  Q_INTERFACES(iTEST)  
  void doB(void): // custom to derived
}

Also, the interface needs a slight modification:

...
  virtual ~iTest(void){}
...

This is due to the fact that the destructor needs to be defined, and cannot be pure virtual. With these modifications, this structure seems to work in my application.

  • Your empty `virtual ~iTest(void){}` can become `virtual ~iTest() = default` and the compiler will take care of the rest. Also, I don't think it's a common practice to add the `void` type in function signatures, at least in C++ and especially to the destructors. – Petross404 Mar 30 '22 at 16:59