PDA

View Full Version : Interface composition and QObject



brcain
17th November 2006, 16:09
The following was never really answered ... see thread (http://www.qtcentre.org/forum/f-qt-programming-2/t-object-and-multiple-inheritance-for-interfaces-4457.html) for background.

Is it a true statement that "you can't use Qt meta-object system with interface composition"?

With interface composition, it's necessary (at least with C++) to use multiple inheritance. Defined interfaces (abstract base classes that derive from QObject for introspection) are composed to provide a composite interface (via inheriting from multiple base interface classes).

The Qt documentation implies that multiple inheritance of QObject is not supported. However, for me it is working quite well as long as my base classes have unique slot and signal names ... this ambiguity being a problem with multiple inheritance in general ... not just limited to Qt. Is there some other limitation?

The parallel in Java for what I'm trying to do is "a class that implements multiple interfaces".

jacek
17th November 2006, 17:25
The following was never really answered ... see thread (http://www.qtcentre.org/forum/f-qt-programming-2/t-object-and-multiple-inheritance-for-interfaces-4457.html) for background.
Then maybe you should continue the old thread?


Is it a true statement that "you can't use Qt meta-object system with interface composition"?
It depends how do you define an interface. If an interface is a class that contains only pure abstract methods (like in Java), then the answer is: "no, it isn't true".
But in your case, the "interface" is a class derived from QObject, which obviously doesn't fit that definition.


The Qt documentation implies that multiple inheritance of QObject is not supported.
If the docs say it isn't supported then it means that it isn't supported, but not necessarily that it won't work.

The biggest problem is that each signal or slot is internally represented by a number, so in each of the base classes will use the same number for different slots.

Here's an example of qt_metacall:

int Test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QWidget::qt_metacall(_c, _id, _a);
if (_id < 0)
return _id;
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: show1(); break;
case 1: show2(); break;
}
_id -= 2;
}
return _id;
}
If you have several base classes then it should look like this:
int Test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
if( _id belongs to Base1 ) {
_id = Base1::qt_metacall(_c, _id - base1offset, _a);
}
else if( _id belongs to Base2 ) {
_id = Base1::qt_metacall(_c, _id - base2offset, _a);
}
if (_id < 0)
return _id;
...
}
or:

Test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
...
if (_c == QMetaObject::InvokeMetaMethod) {
switch (_id) {
case 0: Base1::someSlot1(); break;
case 1: Base2::someSlot2(); break;
...
}
...
}
and of course you will have to write it yourself, as moc won't handle this (it only looks into the first base class).

Another problem is that the QMetaObject for the derived class will be populated only with information about only one base class:

const QMetaObject Test::staticMetaObject = {
{ &Base1::staticMetaObject, qt_meta_stringdata_Test,
qt_meta_data_Test, 0 }
};
While it should be something like this:

const QMetaObject * otherBaseClasses[] = { &Base2::staticMetaObject, 0 };
const QMetaObject Test::staticMetaObject = {
{ &Base1::staticMetaObject, qt_meta_stringdata_Test,
qt_meta_data_Test, otherBaseClasses }
};

In other words, you will have to do all of the work that moc does for you, it it's going to work.

brcain
17th November 2006, 18:48
It depends how do you define an interface. If an interface is a class that contains only pure abstract methods (like in Java), then the answer is: "no, it isn't true".
But in your case, the "interface" is a class derived from QObject, which obviously doesn't fit that definition..

Then I guess I was trying to use Qt for more that what it was created for ... interface composition with runtime introspection. This is considered an industry "best practice" technique.

Do you know of another way to acheive this using Qt ... than the approach I was taking?

Thanks,
Ben

jacek
17th November 2006, 19:05
Do you know of another way to acheive this ... than the approach I was taking?
There's one library that caught my attention, by I didn't have time to check it: http://idioskopos.sourceforge.net/

brcain
17th November 2006, 19:18
Using interface composition ... I also have to throw out signals and slots (as you mentioned above). This is the first design limitation that I've encountered with Qt. I'm not sure what to do to get around this one :(

So, is interface composition just not used that often with Qt?

I will look at idioskopos for the reflective programming. Thanks.

But, there's still the signal/slot problem. I may have to switch to the Boost signals library (hoping it won't have the same multiple-inheritance limitation). But, Qt threads handle signals/slots seamlessly ... calling slots asynchronously when in a different thread. This limitation is very unfortunate.

Chicken Blood Machine
18th November 2006, 05:47
Then I guess I was trying to use Qt for more that what it was created for ... interface composition with runtime introspection. This is considered an industry "best practice" technique.


Considered "best practice" by whom?
Considered "best practice" for what purpose?

It is important to approach C++/Qt with a fresh perspective and not try to enforce paradigms inherited from the baggage of a previously used language, e.g. Java. Think carefully about your intended goal rather than trying to implement some pattern just because that is what you used in the past.

brcain
20th November 2006, 15:39
It is important to approach C++/Qt with a fresh perspective and not try to enforce paradigms inherited from the baggage of a previously used language, e.g. Java.

Save yourself some pain. Learn C++ before learning Qt.


Normally I don't respond to this sort of stuff. But, this was clearly a rant. My statement is true ... was the "first" limitation that I've run into. That's actually a complement. I've been very impressed with Qt. However, there is obviously things Qt wasn't designed to do.

Interface composition is not a language paradigm ... it's a design principle. And your comment on learning C++ before trying to learn Qt. Well, I've been doing C++ programming now for 15 years. So, does that make me qualified?

BTW, I don't even develop in Java ... at least not professionally. But, I do try to follow today's best practice design principles ... some of which are embodied in other languages.

jacek
20th November 2006, 16:02
And your comment on learning C++ before trying to learn Qt. Well, I've been doing C++ programming now for 15 years. So, does that make me qualified?
Look closely --- it wasn't a comment, but a signature. I'm sure it wasn't about you, but a general statement addressed to Qt newbies.

Remember that you are trying to use interface composition on classes, not interfaces. Maybe instead of signals & slots, you could use observer pattern? There's an article (http://www.aspectc.org/fileadmin/publications/sdj-2005-en.pdf) that shows how to do it automagically using AspectC++ (http://www.aspectc.org).

brcain
20th November 2006, 16:19
Maybe instead of signals & slots, you could use observer pattern?

Observer pattern ... used it in the past ... prefer to use the listener pattern instead so the observer and observed don't depend upon one another.

Note I really like the way Qt handles slots with multithreading ... very powerful capability ... automatically handling as an asynchronous event when in another thread. I may use the listener pattern with event queues to nicely handle the threading problems ... since I lose slots ;)

Thanks jacek ... maybe he wasn't trying to be personal. However, it sounded very condescending ... not necessary nor productive for a forum. I've noticed several who respond defensively to criticism in this forum. I've embraced Qt fully ... trying to use it fully ... with design patterns that I've used over the years.

Chicken Blood Machine
20th November 2006, 17:56
Normally I don't respond to this sort of stuff. But, this was clearly a rant. My statement is true ... was the "first" limitation that I've run into.

I wasn't ranting at all, I'm sorry you took it that way. I've learned to become very pragmatic over the years when moving from language to language. I was just suggesting that you consider your final goal rather than trying to use a design that may have made sense in the past, but that Qt has poor support for. My questions were perfectly reasonable: there is no "best practice" without qualification and different problems require different approaches. Often the suitability of these approaches is dictated by the tools and language used.

The simple fact is that interface composition is perfectly possible, you just may have to give up the convenience of signals and slots. Since Java didn't provide this either, I see no real loss. It's certainly worth looking into what Boost signals gives you though.

Oh, and trust me there's nothing defensive at all about my post. I am well aware of the limitations of Qt, just haven't come across anything that was unsurmountable yet.