PDA

View Full Version : Extending two class "the same way"



caduel
22nd July 2009, 20:51
I have a class hierarchy that contains amongst others

class Dialog { ... };
class SpecialDialog : public Dialog { ... };

I also have a class

class ListDialog : public Dialog { ... };

The functionality of "ListDialog" does not depend on the extensions of SpecialDialog, it would have been possible to have it extend SpecialDialog as well.

And that is just my question:
Going from the (already implemented) above classes, is there an easy way to have both a ListDialog and a "SpecialListDialog" that is identical but inherits SpecialDialog instead. (Ideally the solution should allow even further "Dialog"-based classes as subclasses.

I would hate to copy the source and just change the few references to the base class (mostly in virtual methods). I also don't like too many implementation details in headers (otherwise I'd make a template)...

I am aware that I could put the complete implementation into the header and make the class a template and the base class a template parameter. (I am looking for a different solution, if possible.)
Another idea would be to try to put the extension of ListDialog into a separate class and use multiple inheritance. But how would you override the virtual functions, then? (Yes, Dialog does contain virtual methods which are overridden in ListDialog..)

Best regards and thank you for your ideas.

(A similar problem is when you want to extend two different (existing) Qt widgets by common functionality...)

wysota
22nd July 2009, 21:18
To me it seems what you want is more composition than generalization. Basically what you can do is to design interfaces describing each of the "additions" to the Dialog class and then make the "subclasses" implement them. This doesn't have to be through inheritance, the most trivial solution would be to use aforementioned composition.

class A {
public:
virtual void x() = 0;
};
class B {
public:
virtual void y() = 0;
};

class C {
public:
const A* a() const { return &m_AImpl; }
const B* b() const { return &m_BImpl; }
private:
AImpl m_AImpl; // where AImpl inherits A
BImpl m_BImpl; // where BImpl inherits B
};

This is more or less what is done in Qt Creator and is called aggregation there.

What Creator uses is a kind of dynamic aggregations where you can add objects to the "mother-object" on demand. Unfortunately I can't find any articles about such a feature right now. In general you can query an object for an interface and if it has sub-object implementing it, they will be returned.

caduel
22nd July 2009, 22:43
Thank you, I will think about that.
The only annoying thing is that this are not "pure" additions, but the ListDialog does reimplement several virtual methods. It is not obvous how to best deal with several such additions as in your example that all might reimplement a, say, keyHandler() to handle some keys...

wysota
22nd July 2009, 22:55
The only annoying thing is that this are not "pure" additions, but the ListDialog does reimplement several virtual methods.
Those virtual methods may be an object in the base class as well.


It is not obvous how to best deal with several such additions as in your example that all might reimplement a, say, keyHandler() to handle some keys...

Very easy. The base class asks the current object if it implements this particular interface and if so, it delegates the call to it.


class Base {
public:
virtual void keyHandler(int x){
// the method doesn't even need to be virtual (which maintains binary compatibility by the way)
KeyHandlerIface *kh = objectFor<KeyHandlerIface*>(this); // ask "this" aggregate to return "KeyHandlerIface" object
if(kh){
kh->handleKey(x);
} else {
//...
}
}
};

Of course you need to build upon this, objectFor() needs to be implemented using templates and/or qobject_cast.