From: Jacek S. <arn...@gm...> - 2007-03-05 16:51:33
|
Hello, I'm playing with an MDI application and I ran into a rather fundamental smartwin design issue (ok, that's a point of view =) that made me lose half a day (although I'm not very good at c++). It all boils down to the use of virtual inheritance and constructors that that parameters for the Widget class. Since virtually inherited classes are initialized before all other classes, there are a few nasty surprises to run into when using the smartwin api. I was reading the docs for widgetfactory that has a constructor that takes a parent pointer. I did the most obvious thing - I passed along a parent pointer from my own constructor to the WidgetFactory constructor expecting it to set the parent pointer of the Widget class so I could use getPointer() later (actually, so createMDIChild could use Widget::itsPointer). I did all kinds of debugging while I was passing in a perfectly valid pointer that seemed to be passed along into each constructor up the inheritance chain, Widget::itsParent remained 0. It's worth noting that the widgetfactory constructor passes the parent to the Widget constructor and to WidgetFactoryPlatformImplementation->ContainerWidgetType->Widget(Again!). I'm not sure what the author of those classes intended, because by the time the WidgetFactory constructor is called from any class inhering from WidgetFactory, it's already way too late to be initializing Widget - virtually inherited classes are initialized before all others. All that those unneeded constructor calls do is to confuse whoever is reading the code into thinking that Widget will actually be called with parent set to a meaningful value, while in reality it's called using the default value 0 (put a printf in the widget constructor if you don't believe me). To make this even more of a problem (again I wonder what the reason for doing this way was - the comment above the constructor tells of ignorance of this issue), the Widget constructor not only takes parameters, but intentionally hides the fact by supplying defaults, so the smartwin library user (me =) has *no* way of knowing that the constructor was called with the wrong parameters - normally the compiler would have stopped me. So, here's a quiz to sum up: #include <SmartWin.h> using namespace SmartWin; struct A : public WidgetFactory<WidgetMDIChild, A> { A(Widget* parent) : WidgetFactory<WidgetMDIChild, A>(parent) { } }; int SmartWinMain(Application& app) { Widget* parent = (Widget*)123; A* a = new A(parent); printf("%d\n", (int)a->getParent()); return 0; } What do you expect to be printed? Regards, Jacek Sieka |