For the "too long; didn't read" crowd, just read the four boldface sentences. The rest is explanation. :-)
@drjdpowell and @flintstone:
A child class that does something the parent never intended is a bad child class in almost all cases. The phrase "And you as the parent class designer do not know now what your class might be used for in e.g. three years from now" is false. The parent class designer establishes, in stone as it were, exactly the uses of a child class. Why? Because code will be written that uses the parent class and only the parent class, and that code knows nothing about the children that will eventually flow through it. All children are expected to match those expectations or they are going to have runtime problems. The more you can convert those runtime problems into compile time problems by letting the parent declare "these are the requirements", the more successful the authors of the child classes will be. This is true whether you are one developer working on an app by yourself or whether you are writing a framework for third party developers to plug into.
A child class needs to match it's parents for Identity, State and Behavior or else a child cannot be effectively used in any framework written for the parent. The parent defines the invariants that all child classes will obey -- that's what allows frameworks to operate. The more that a language allows a parent to say "these are the exact requirements needed to be a well defined version of myself", the more power the language has to build frameworks that are guaranteed to work out of the box. The parent designs for "the children will have free reign to do whatever they want here" and "the children will do exactly this and nothing else here".
I'll give you an example that we were discussing yesterday: dynamic dispatch on FPGA. At the moment, the parent implementation of a dynamic dispatch method just defines the connector pane of the method. It does not define the cycle time of the method. In order to write an FPGA framework where any child class can be plugged in and the framework works, there are cases where you need to be able to guarantee that the child override will execute in the same number of clock cycles as the parent implementation defines. Essentially, the parent implementation needs a way to say "I have three Feed Forward nodes on my diagram in series between this input and this output. I require all overrides to maintain the same amount of pipelining... their diagrams must have exactly three Feed Forward nodes in series." We were discussing ways to add that restriction declaration to LabVIEW and whether the compiler could really check it.
I have plenty of other examples, from many languages, of parent classes that want to define particular limitations for children. LabVIEW has the scope restrictions, the Must Override restrictions, the DVR restrictions [particularly the one that says this one ancestor is the only one that can create DVRs for all the descendants]. When we someday have template classes, we'll have the ability for the parent class to set type limits, just like every other language that has templates.
If you are defining a class that is a lot like a parent but violates Identity, State or Behavior, do not use inheritance; use containment instead. Delegate to a contained instance of the parent class when (if) appropriate. Or define a new grandparent class for the parent and move the common functionality up to the grandparent such that the invariants of the parent class are unchanged and you can now inherit off of the grandparent to get ONLY the functionality that your new piece requires.
> (if you still can open it in your then current version of LV )
We just last year walked a LV 4.0 VI all the way to LV 2012. It opened and ran just fine. You have to open it in LV 6.0, then LV 8.0 then LV 2012, as those are the defined load points, but the mutation paths have been fully maintained.