Hi Jurgen,
I sent my note off after several hours wasted rediscovering the bug. I am less frustrated now and working around the issue. The main frustration was not the bug itself but the fact that it was not documented anywhere and then realizing that it ruled out the most elegant solution!
Question: what is the runtime overhead associated with BaseObject.x versus BaseClass::x?? I did an experiment and come up with the latter taking 82% of the time of the former. Is that roughly correct?
I disagree slightly that the 3 other solutions are comparable. They are okay when you are programming for yourself. But when implementing a solution that calls for end users to construct their own derived classes it is dangerous to use any static members in the base class.
Consider this:
class Base { static decl x; }
class UserDerived : Base { usermethod(); }
UserDerived::usermethod() { dosomethingwith(Base::x) }
You are saying: advise users to always write Base::x. But if the user just types dosomething(x) they do not get an error. They will get output based on dosomething(0), because UserDerived::x gets initialized to 0. As the writer of Base I cannot stop UserDerived::x from being initialized. If I could then the user's mistake would cause a runtime error and my documentation could explain it to them. They would revert to Base::x and all is good. But like me they can be perplexed and possibly led astray by code that uses UserDerived::x that they do not realize exists let alone is different than Base::x.
A solution to this problem is to do this:
struct BaseStatic { static x; ... }
static decl Hidden = new BaseStatic(); //I know you can't actually assign outside of {}.
class Base { const decl BS; Base(); }
Base::Base() { BS = Hidden; }
Now all classes derived from Base get access to x using BS.x. The user or me can also use BaseStatic::x for efficiency, but as long as the user is not required to write a class derived from BaseStatic there is no confusion and no possibility that BS.x refers to one thing in their code and another in mine. And BaseStatic can have a mix of static and non-static members.
This is obviously less elegant and creates some problems of its own. For example, UserDerived() could set BS to something else, but they would get runtime errors if they tried to access BS.x.
--CF
|