An OpenGL window should not be running around casting OpenGL controls to a long list of all possible children types, that is just madness. That is an unmanageable, unextendable non-oo design. However each OpenGL control can and likely will cast the IWindow to an IOpenGL window (fully expecting it to be one, since the whole assumption is the creation of everything from exactly 1 factory instance, so that a mismatch would be impossible. Also, an OpenGL window would keep a list of IOpenGL controls, and cast each control on add from IControl to IOpenGL control ... because the open gl family is going to be implemented internally to receive, associate with and use only other open gl family controls. The base interfaces are just used as the lesser API for externally facing interfaces.
Keep in mind that my casts "to a list of all possible children types" was an illustration of what
not to do. Then, I offered another solution that is very similar to what you proposed:
[source lang="cpp"]void addControl(Control *ctrl)
{
Foo::Control *fooCtrl = dynamic_cast(ctrl);
if(fooCtrl!= NULL)
{
m_window.addControl(fooCtrl);
}
}[/source]
There is a problem with this, though. It works, but there is a bit of ugliness which I can't seem to get around, which is that it almost inevitably requires multiple inheritance. Here is one possible hierarchy (this time using OpenGL as an example, as you did).
OpenGLControl could also derive from IControl, but then you'd have diamond inheritance. You could use virtual inheritance to solve that; in fact, it's probably a good idea to do that anyway, because if your hierarchy gets any deeper (think ISwitchButton and IRadioButton), you're going to end up with diamond inheritance anyway. Once you have diamond inheritance, virtual inheritance becomes and issue, and once you have virtual base classes, you can no longer downcast them using static_cast, which means that SiCrane's checked cast solution is out of the question.
So, let's suppose that you keep your hierarchy clean enough that there are no diamonds, and thus virtual inheritance is unnecessary. Well, you still have multiple inheritance, which lends overhead to dynamic casting (and static casting too, if I understand it correctly) because now you have multiple vtables in your object, and a cast involves offsetting the pointer.
These are the sorts of ugly sins that I've been dealing with with this design.
I am warming up to Telastyn YAGNI remark. As jwezorek said, it may be impractical to think that I can wrap everything that I need to, even future frameworks that I haven't thought of yet.
dmatter, thank you very much for your reply. It seems to be clearest way to put into words what I'm doing wrong. The duck typing idea sounds intriguing, but I think my project is a bit too complicated for that. Your idea for having the window produce controls is also intriguing. It seems like it would be difficult to ever close the Window class to modification, though, because every time you come up with a new control type, you have to add a new method. Still, that may be a lesser sin than violating LSP.