PDA

View Full Version : Plugin Adapter Classes?



SixDegrees
25th April 2010, 13:26
So we've built a plugin system. We have an abstract base class filled with pure virtual function definitions, and several derived classes that flesh out these functions and get built as shared objects. All of this works extremely well, and was simple to implement.

However, we would now like to extend this framework by inserting a Java-style "adapter class" between the abstract base class and its derivatives, so users who don't need to implement the entire interface can fall back on the default behavior defined in the adapter. Although I'm not a big fan of adapter classes, this has the benefit of somewhat insulating the end user from changes to the interface, since additions to the interface will not require the user to modify and recompile their plugin code.

Unfortunately, this doesn't seem to work with the plugin framework provided by Qt. We derive the adapter class from the base class, then derive the actual "working" class from the adapter, but at runtime the plugin loader doesn't recognize the library as a valid plugin, and returns 0. Note that we cannot include the Q_EXPORT_PLUGIN2 anywhere but in the "working" plugin. It cannot be included in the adapter class, because it can only occur once in any given library. But it seems that the loader won't recognize the plugin as valid unless it inherits directly from the abstract base class. Going through an intermediate class breaks whatever paradigm is being used, and results in runtime failure to load the library.

Any thoughts on how to accomplish this, or on whether it is even possible under the Qt plugin framework?

wysota
25th April 2010, 15:57
Although I'm not a big fan of adapter classes, this has the benefit of somewhat insulating the end user from changes to the interface, since additions to the interface will not require the user to modify and recompile their plugin code.
If I understand correctly what you mean then that's not true. Addition of a virtual method to a base class requires recompilation of all subclasses (as the virtual table size and possibly offsets change).


Note that we cannot include the Q_EXPORT_PLUGIN2 anywhere but in the "working" plugin.
Why not?


It cannot be included in the adapter class, because it can only occur once in any given library. But it seems that the loader won't recognize the plugin as valid unless it inherits directly from the abstract base class.
Naah, that's shouldn't be the case.


Any thoughts on how to accomplish this, or on whether it is even possible under the Qt plugin framework?
Please prepare a minimal compilable example reproducing the problem.

MorrisLiang
25th April 2010, 15:57
Well,the plugin thing is actually kind of difficult for me.According to the QT tutorial I read,plugins have to inherit from an interface,so the QPluginLoader will recognize them.
But if you take a look at QtCreator's source code,you wil find that it doesn't use marcos like Q_EXPORT_PLUGIN2().Besides,all the plugins inherit from a abstract base class called IPlugin(not interface).And the QPluginLoader still loads them.
And I want to know why too...

wysota
25th April 2010, 16:43
Well,the plugin thing is actually kind of difficult for me.According to the QT tutorial I read,plugins have to inherit from an interface,so the QPluginLoader will recognize them.
But if you take a look at QtCreator's source code,you wil find that it doesn't use marcos like Q_EXPORT_PLUGIN2().Besides,all the plugins inherit from a abstract base class called IPlugin(not interface).And the QPluginLoader still loads them.
And I want to know why too...

Please don't cross-post. What you say has nothing to do with the subject. Plus you have already been answered in the other thread so don't continue writing false statements.

SixDegrees
25th April 2010, 20:50
http://doc.trolltech.com/4.2/qtplugin.html#Q_EXPORT_PLUGIN2:

[QUOTE]There should be exactly one occurrence of this macro in the source code for a Qt plugin, and it should be used where the implementation is written rather than in a header file.

SixDegrees
25th April 2010, 20:58
Well,the plugin thing is actually kind of difficult for me.According to the QT tutorial I read,plugins have to inherit from an interface,so the QPluginLoader will recognize them.
But if you take a look at QtCreator's source code,you wil find that it doesn't use marcos like Q_EXPORT_PLUGIN2().Besides,all the plugins inherit from a abstract base class called IPlugin(not interface).And the QPluginLoader still loads them.
And I want to know why too...

I had no trouble at all implementing an interface and several plugins, following Trolltech's examples. They work perfectly. The problem here is trying to implement something akin to Java-style "adapter classes," where an intermediate class with implementation of the pure virtual functions declared in the interface is used to ease creation of inherited classes.

I suspect that the Qt framework only allows inheritance directly from the abstract base class. At least, that seems to be the case in practice, as noted.

wysota
25th April 2010, 21:10
Why not?

http://doc.trolltech.com/4.2/qtplugin.html#Q_EXPORT_PLUGIN2:

Sorry, I misunderstood you. I though you have written that you were unable to put it in the "working" plugin. You have to put it there, it wouldn't make sense to put it elsewhere.


I suspect that the Qt framework only allows inheritance directly from the abstract base class. At least, that seems to be the case in practice, as noted.
"Qt framework" has nothing to do with this. C++ enforces some rules but it is perfectly valid to inherit from an implementation of a pure abstract class.


class Interface {
public:
virtual void func1() = 0;
virtual void func2() = 0;
};

class Implementation : public Interface {
public:
void func1() { printf("Implementation::func1();\n"); }
void func2() { printf("Implementation::func2();\n"); }
};

class Inherited : public Implementation {
public:
void func2() { printf("Inherited::func2();\n"); }
};

You can do the same with Qt plugins, only that you have to remember you should inherit from QObject somewhere.

SixDegrees
25th April 2010, 21:33
Unfortunately, the loader won't recognize Inherited. As you mention, we put the export macro there, along with Q_OBJECT, per the instructions in the examples. Just for grins, we tried putting it in the Implementation class, too; when we did that, the loader would recognize Implementation, but not, of course, Inherited.

This doesn't break my heart; as I said originally, I don't care much for adapter classes, and not being able to do this isn't that big a deal.

You may be right about the offset issue, anyway. We've done something similar in "raw" C++, but only on Solaris. We may have gotten lucky and exploited a peculiarity of the Solaris linker that wouldn't travel well.

wysota
25th April 2010, 22:10
You must be doing something wrong - it works for me just fine. Attached you will find a working example - if you are using Linux, just run run.sh, otherwise you'll have to adjust the script first and replace LD_LIBRARY_PATH with an equivalent on your system.

Edit: please edit run.sh and remove "make clean" calls, it seems one of them breaks something.

MorrisLiang
26th April 2010, 07:05
Please don't cross-post. What you say has nothing to do with the subject. Plus you have already been answered in the other thread so don't continue writing false statements.

OK,I saw the replies on my post after I replied on this one.I might misunderstand what SixDegrees wants to do.But I think maybe QtCreator's source code would be somewhat helpful.

SixDegrees
26th April 2010, 07:38
You must be doing something wrong - it works for me just fine. Attached you will find a working example - if you are using Linux, just run run.sh, otherwise you'll have to adjust the script first and replace LD_LIBRARY_PATH with an equivalent on your system.

Edit: please edit run.sh and remove "make clean" calls, it seems one of them breaks something.

Thanks for your time, but these examples are not implemented as plugins. Inheritance certainly works - it's C++, after all. But when I do use the same paradigm and try to implement it as a plugin, the plugin loader fails to recognize Inherited as a legitimate plugin.

wysota
26th April 2010, 09:39
Thanks for your time, but these examples are not implemented as plugins.
Yes, they are. Look at the .pro files - I'm not linking libinherited.so into the "main" program. I think libimpl.so could also be made a plugin but libinherited.so has to link against it nevertheless so it will act as a regular library too.

Edit: Just checked it, you can load libimpl.so as a plugin too, just remember about adding the proper export macro.