What is the difference between the override
and reintroduce
directives? And when should I not use the inherited
keyword in overridden methods?
The reference to Jim's answer, which was excellent BTW, only described the when and where to use the directives. Another part of the answer is why are they needed anyway? Many languages get along just fine without them, right? When designing aspects of the Delphi Object Pascal Language, OOP (Object Oriented Programming) had been in the mainstream for several years. During this time it was observed that using many of the languages that had adopted those concepts (Turbo Pascal, C++, etc..) to develop application frameworks suffered from what I called the "version 2" problem.
Suppose you developed an awesome framework using language X and released it as version 1. Your users raved at all it could do and it became heavily used. Flush with success, you decide to release version 2 with even more awesomeness. You specifically made sure it was fully backward compatible. Suddenly, you users started reporting strange behaviors. Their own virtual methods were being called at strange times. Many reported that their old code would not compile with the new version. Strange. All the same objects, methods, and functionality still remained. All you did was add a few virtual methods to some base classes, some new object types, and some new optional functionality. What happened?
The override and reintroduce directives serve to eliminate this problem by requiring that in order to actually override a virtual method you must use the override directive in place of the virtual directive. If you happen to introduce your own virtual method that has the same name as one of your ancestors' virtual methods, the compiler now warns you, but will still do the right thing. In this case, using reintroduce, not only suppresses that warning, it also serves to document in the source you intended to do that.
Without the override and reintroduce directives, you would not be able to continually evolve your framework without fear of breaking all your users. And if your users had to make massive modifications every time a new version is released, then they would be loathe to adopt the new version. Finally, using "override" also allows the framework designer to change the type of virtual in the ancestors without breaking user code. For instance, in Delphi many methods are marked "dynamic" which is a table-based runtime method lookup form of polymorphism. It's doesn't perform quite as fast as a regular virtual so it is usually used for methods that are rarely overridden and/or are responses to user actions where the extra overhead is never noticed. Suppose in V1 of the framework a method was marked "dynamic" but in practice it ended up being overridden and called more than you intended. In V2, you could change it to "virtual" without fear of user's code being broken.
Delphi's Object Pascal language isn't the only language to recognize this problem. C# requires the use of an "override" directive for the exact same reason. The C++ standards committee is finally recognizing the problem and are modifying the language to support it... sort of. In C++, if a method's name and parameter list matches an ancestor's virtual, then it is an override (even if you don't say "virtual" on the descendant!). For the upcoming new C++ standard, if you specify "virtual" and the signatures don't match then it is a new virtual method introduced on current class. If there is a signature match with the ancestor and the writer didn't intend to override, then the "new" keyword is used to tell the compiler that this is a new virtual for this class.
override
keyword in his/Apple's Object Pascal (for the Mac), very likely for the same reason. And MS QuickPascal had it too. But neither had a reintroduce
. –
Geum new
in C++, but the Delphi part is very informative. Thanks for completing the override
story I already knew. –
Xenomorphic The override directive is used to override virtual methods in inherited classes.
The reintroduce directive is used to declare a method with the same name as in the super class, but with different parameters.
but with different parameters
. –
Xenomorphic And when should I not use the inherited keyword in overridden methods?
Basically, the answer is when you don't wish the inherited method to execute. Be careful though as not allowing an inherited method to run may break functionality of an inherited object in a undesirable way, so make sure you are not introducing any unintended side effects.
As an example, imagine you wish to fully override an inherited function called ApplyDiscount, but someone has hardcoded the discount percentage into the ancestor class. If you call the inherited ApplyDiscount it will override your code or calculate a value you will then override; in this case you could just not call inherited and apply the discount yourself.
(This is a contrived example so if someone can think of a better one please add it.)
There are many circumstances where you don't want to call inherited in an overridden method.
In some libraries that I use, the base method throws an error (ENotImplimented or similar). Obviously in that case you don't want to call inherited or your code would also throw the error.
Some of my classes have a default implementation that works in the majority of cases. The method is only overridden to replace the default, and there is no need to call the default.
For example, the GST function (= sales tax) on my base financial object returns 12.5% of the ExGst amount and IncGst returns ExGst + GST.
On my Income Compensation objects, GST always returns 0, so there is no need to call the inherited function.
© 2022 - 2024 — McMap. All rights reserved.