PDA

View Full Version : Multiple inherittance in plugins



KShots
20th April 2007, 18:10
I'm hitting a wall here. I have a plugin interface that needs signals and slots (so must subclass QObject and have the Q_OBJECT macro), then my subclasses (or my plugins, as it were) need to inherit both my interface and either QWidget or something similar (like QGLWidget).

Unfortunately, when I inherit both my interface and QWidget, my compiler is telling me that QObject is an ambiguous base of my plugin. This appears to stem from the Q_EXPORT_PLUGIN2() macro. Here's the exact compiler output:
evilcpcMenuAeon.cpp: In function 'QObject* qt_plugin_instance()':
evilcpcMenuAeon.cpp:33: error: 'QObject' is an ambiguous base of 'evilcpcMenuAeon'
/usr/include/qt4/QtCore/qpointer.h: In member function 'QPointer<T>::operator T*() const [with T = evilcpcMenuAeon]':
evilcpcMenuAeon.cpp:33: instantiated from here
/usr/include/qt4/QtCore/qpointer.h:58: error: 'QObject' is an ambiguous base of 'evilcpcMenuAeon'
/usr/include/qt4/QtCore/qpointer.h: In member function 'QPointer<T>& QPointer<T>::operator=(T*) [with T = evilcpcMenuAeon]':
evilcpcMenuAeon.cpp:33: instantiated from here
/usr/include/qt4/QtCore/qpointer.h:48: error: 'QObject' is an ambiguous base of 'evilcpcMenuAeon'
/usr/include/qt4/QtCore/qpointer.h:48: error: 'QObject' is an ambiguous base of 'evilcpcMenuAeon'
make[1]: *** [release/evilcpcMenuAeon.o] Error 1
make[1]: Leaving directory `/home/rich/svn/evilcpc/trunk/plugins/menu/aeon'
make: *** [release] Error 2Is there any way around this?

fullmetalcoder
20th April 2007, 18:33
I'm hitting a wall here. I have a plugin interface that needs signals and slots (so must subclass QObject and have the Q_OBJECT macro), then my subclasses (or my plugins, as it were) need to inherit both my interface and either QWidget or something similar (like QGLWidget).

Unfortunately, when I inherit both my interface and QWidget, my compiler is telling me that QObject is an ambiguous base of my plugin. This appears to stem from the Q_EXPORT_PLUGIN2() macro. Here's the exact compiler output:Is there any way around this?
I think I've already answered this in another threads of yours but anyway :

plugin interfaces must be abstract classes (so no inheritance from non-abstract classes, and especially not from QObject)
multiple inheritance needs so called virtual inheritance in ancestor classes
by design, multiple inheritance from QObject is IMPOSSIBLE so just forget about it and find another design...Hope this helps. :)

wysota
20th April 2007, 18:45
Be careful when you use the term "virtual inheritance". Multiple inheritance doesn't require virtual inheritance.

fullmetalcoder
20th April 2007, 19:25
Be careful when you use the term "virtual inheritance". Multiple inheritance doesn't require virtual inheritance.
Is there a misunderstanding here??? By "virtual inheritance" I mean use of "virtual" keyword in front of regular inheritance declaration which is needed to disambiguate names in case of multiple inheritance... This little FAQ section (http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.9) might be clearer than my poor explanations anyway...

KShots
20th April 2007, 19:36
I think I've already answered this in another threads of yours but anyway :

plugin interfaces must be abstract classes (so no inheritance from non-abstract classes, and especially not from QObject)
multiple inheritance needs so called virtual inheritance in ancestor classes
by design, multiple inheritance from QObject is IMPOSSIBLE so just forget about it and find another design...Hope this helps. :)Hmm... so in this case I should attempt to use boost (http://www.boost.org/doc/html/signals/tutorial.html#id2733461) signals and slots rather than Qt signals and slots for my plugin interface? The only reason I wanted QObject was for signals and slots.

Alternatively, I suppose I could put the signals and slots into my plugin classes and use QMetaObject to parse all the available methods for signals and slots... but that seems a lot of effort. Any other way of doing something similar?

wysota
20th April 2007, 20:21
Is there a misunderstanding here??? By "virtual inheritance" I mean use of "virtual" keyword in front of regular inheritance declaration which is needed to disambiguate names in case of multiple inheritance...

This only applies if the superclasses both inherit another (the same) class and by itself it doesn't yet mean virtual inheritance is required.


class A{};
class B{};
class C : public A, public B {}; // this doesn't require "virtual" anywhere
class D : public A{};
class E : public C, public D{}; // this doesn't _require_ A to be "virtual" in C and D
// but it might be needed depending on how you use the classes


Hmm... so in this case I should attempt to use boost (http://www.boost.org/doc/html/signals/tutorial.html#id2733461) signals and slots rather than Qt signals and slots for my plugin interface? The only reason I wanted QObject was for signals and slots.

The plugin itself doesn't have to inherit the actual functionality you require. It may simply return an instance of a class inheriting some common base.


class Blah : public QObject { ... };

struct Plugin : public QObject, public SomeInterface{
Q_OBJECT_AND_STUFF
Blah *createInstance(QObject *parent=0){
return new BlahSubclass(parent);
}
};

fullmetalcoder
21st April 2007, 09:51
This only applies if the superclasses both inherit another (the same) class and by itself it doesn't yet mean virtual inheritance is required.


class A{};
class B{};
class C : public A, public B {}; // this doesn't require "virtual" anywhere
class D : public A{};
class E : public C, public D{}; // this doesn't _require_ A to be "virtual" in C and D
// but it might be needed depending on how you use the classes

Yeah, sure... But in the case we were discussing I implicitly pre-supposed MI to involve the same base...



The plugin itself doesn't have to inherit the actual functionality you require. It may simply return an instance of a class inheriting some common base.


class Blah : public QObject { ... };

struct Plugin : public QObject, public SomeInterface{
Q_OBJECT_AND_STUFF
Blah *createInstance(QObject *parent=0){
return new BlahSubclass(parent);
}
};
This is not a solution... the reason for plugin interfaces to be abstract is that it frees the plugin from dependency to an intermediate library storing implementations of methods that would be defined in the interface... Using an abstract class limits the dependency to a single header file whereas using complex (i.e. non-abstract) classes that must be known to both the app and its plugins force to rely on an intermediate shared library which contains all base plugin classes specifications... (and believe me, this is not an easy way to go, even if its brings great power...)


Alternatively, I suppose I could put the signals and slots into my plugin classes and use QMetaObject to parse all the available methods for signals and slots... but that seems a lot of effort. Any other way of doing something similar?
The use of QMetaObject is not required directly here... As the plugin instance creator returns a QObject you can just connect it as if signals/slots were defined in the base class (but then you just assume their presence and a badly implemented plugin could break this logic...)

wysota
21st April 2007, 12:10
This is not a solution... the reason for plugin interfaces to be abstract is that it frees the plugin from dependency to an intermediate library storing implementations of methods that would be defined in the interface...
Strange, because Qt uses the exact same method for providing widget plugins for Designer... And as far as I know other component technologies (like COM) use that approach as well...


Using an abstract class limits the dependency to a single header file whereas using complex (i.e. non-abstract) classes that must be known to both the app and its plugins force to rely on an intermediate shared library which contains all base plugin classes specifications... (and believe me, this is not an easy way to go, even if its brings great power...)
But where does my approach violate any of the above mentioned statements? I don't see a problem for "Blah" being an abstract class declared in the same file as "SomeInterface"...

fullmetalcoder
22nd April 2007, 19:20
Strange, because Qt uses the exact same method for providing widget plugins for Designer... And as far as I know other component technologies (like COM) use that approach as well...
All the dependencies are NOT in Qt Designer itself but in Qt libs, including QtDesigner and QtDesignerComponents library... ;)


But where does my approach violate any of the above mentioned statements? I don't see a problem for "Blah" being an abstract class declared in the same file as "SomeInterface"...
It will be OK as long as Blah inherits ONLY from Qt classes, or other external libraries BTW, (thus accessible from the plugin without the need to create an intermediary library) AND does not implement any method of its own (except inline methods and possibly, but might depend on compiler, methods implemented inside the header file).

wysota
22nd April 2007, 19:44
All the dependencies are NOT in Qt Designer itself but in Qt libs, including QtDesigner and QtDesignerComponents library... ;)
The only dependency is QObject and obviously you need that anyway to create Qt plugins.


It will be OK as long as Blah inherits ONLY from Qt classes, or other external libraries BTW, (thus accessible from the plugin without the need to create an intermediary library) AND does not implement any method of its own (except inline methods and possibly, but might depend on compiler, methods implemented inside the header file).

I don't see how moving those "non-inline" methods to the interface class would help. And besides that's really not a problem - you can create a library with symbols needed by the plugin and you're there. Exactly like Qt and Designer do it.

fullmetalcoder
23rd April 2007, 19:31
you can create a library with symbols needed by the plugin and you're there.Isn't that what I was saying??? Basically if your INTERFACE (which according to the docs should abstract) DOES IMPLEMENT some methods it may be necessary to create such an intermediary shared library with all the symbols that are used by both the app and plugins. Otherwise the headers are enough and that's the way suggested by the docs because it obviously make things MUCH simpler...


Exactly like Qt and Designer do it. Designer does not have any problem because, as I've said already it is a wrapper app around several libraries (namely QtDesigner and QtDesignerComponents) and plugins.

wysota
23rd April 2007, 21:03
I don't really see a problem in doing this the way I said :) I made a few plugins in my life (both using and not using the Qt plugin framework) and they always worked as expected in the form I suggested. COM seems to work too, Java implementing interfaces seems to work, other languages as well... I don't really see a problem in creating an implementation of an interface that returns an instance of implementation of another interface...

I think it should look more or less like so:

struct MyInterface {
virtual void method1() = 0;
virtual void method2() const = 0;
virtual int method3() = 0;
virtual double method4(int) = 0;
virtual ~MyInterface(){}
};

struct PluginInterface {
virtual ~PluginInterface(){}
virtual MyInterface *create(QWidget *parent=0) = 0;
};
Q_DECLARE_INTERFACE(PluginInterface, "xxx")

And implementation:


struct MyInterfaceImpl : public QObject, public MyInterface {
MyInterfaceImpl(QWidget *parent = 0) : QObject((QObject*)parent){}
void method1(){ printf("BLABLA\n"); }
void method2() const { printf("BLABLA\n"); }
int method3() { return 7; }
double method4(int a) { return a*1.0/7.0; }
~MyInterfaceImpl(){}
};

struct Plugin : public QObject, public PluginInterface {
Q_OBJECT
Q_INTERFACES(PluginInterface)
Plugin(QObject *parent=0) : QObject(parent){}
~Plugin(){}
MyInterface *create(QWidget *parent=0){ return new MyInterfaceImpl(parent); }
};

fullmetalcoder
24th April 2007, 20:23
I don't really see a problem in doing this the way I said :) I made a few plugins in my life (both using and not using the Qt plugin framework) and they always worked as expected in the form I suggested. COM seems to work too, Java implementing interfaces seems to work, other languages as well... I don't really see a problem in creating an implementation of an interface that returns an instance of implementation of another interface...
I did NOT say this was a problem... Your example works pretty fine because both classes are INTERFACES and don't IMPLEMENT any method of their own... They just provide pur virtual methods that pligin implementation MUST subclass... What I pointed out as a source of trouble was non-abstract classes used as interfaces...

Hope this make my explanations a little clearer...:)

wysota
24th April 2007, 20:27
An interface is by definition a class that's pure abstract. And I don't consider a need to use an external library "trouble", by the way.