Why is the default decision in C++, C#, and Ada 95 to use static method binding, rather than dynamic method binding.?
Is the gain in implementation speed worth the loss in abstraction and re-usability?
In general, you can consider that you have todesign the base class for extensibility. If a member function (to use the C++ vocabulary) isn't designed to be overridden, there is a good chance than overriding it will in practice not be possible and for sure it won't it be possible without knowledge of what the class designer think is implementation details and will change without giving you prior notice.
Some additional considerations for two languages (I don't know C# enough to write about it):
Ada 95 would have had compatibility issues with Ada 83 if the choice was different. And considering the whole object model of Ada 95, doing it differently would have make no sense (but you can consider that compatibility was a factor in the choice of the object model).
For C++, performance was certainly a factor. The you don't pay for what you don't use principle and the possibility to use C++ just as a better C was quite instrumental in its success.
The obvious answer is because most functions shouldn't be virtual. As AProgrammer points out, unless a function has been designed explicitly to be overridden, you probably can't override it (virtual or not) without breaking class invariants. (When I work in Java, for example, I end up declaring most functions final
, as a matter of good engineering. C++ and Ada make the right decision: the author must explicitly state that the function is designed to be overridden.
Also, C++ and (I think) Ada support value semantics. And value semantics doesn't work well with polymorphism; in Java, classes like java.lang.String
are final
, in order to simulate value semantics for them. Far to many applications programmers, however, don't bother, since it's not the default. (In a similar manner, far too many C++ programmers omit to inhibit copy and assignment when the class is polymorphic.)
Finally, even when a class is polymorphic, and designed for inheritance, the contract is still specified, and in so far as is reasonable, enforced, in the base class. In C++, typically, this means that public
functions are not virtual, since it is the public functions which define and enforce the contract.
I can't speak about Ada, but for C++ two important goals for the design of C++ were:
- backwards compatibility with C
- you should pay nothing (to the extent possible) for features that you don't use
While neither of these would necessarily dictate that dynamic binding couldn't have been chosen to be the default, having static method binding (I assume you mean non-virtual member functions) does seem to 'fit' better with these design goals.
I'll give one of the other two thirds of Michael Burr's answer.
For Ada it was an important design goal that the language be suitable for system's programming and use on small realtime embedded devices (eg: missile and bomb CPUs). Perhaps there are now techniques that would allow dynamic languages to do such things well, but there certianly weren't back in the late 70's and early 80's when the language was first being designed. Ada95 of course could not radically deviate from the orginal language's basic underlying design, any more than C++ could from C.
That being said, both Ada and C++ (and certianly C# as well?) provide a way to do dynamic method binding ("dynamic dispatch") if you really want it. In both it is accesed via pointers, which IMHO are kind of error-prone. It can also make things a bit of a pain to debug, as it is tough to tell from sources alone exactly what is getting called. So I avoid it unless I really need it.
精彩评论