Introducing Type Inheritance - Delphi OOP Part 6 - Chapter 13

106 149
Materials written by John Barrow. Modifications by Zarko Gajic
Back to Chapter 12

Introducing (in this Chapter):
  • Polymorphism = substitution + dynamic binding

Alternatives to polymorphism

Newcomers to OO sometimes feel reluctant to exploit polymorphism; it seems too strange. How important is it? What are the alternatives? In this case, because this is such a simple example, the easiest alternative is not to subclass at all.

Instead we can just declare an attribute in the TFurniture class to indicate Furniture, Chair, or Table. But in cases where the differences between subclasses are more extensive, combining everything into a single class leads to a class that is very big and unwieldy, and makes future change and maintenance very difficult. So can we retain the hierarchy of three separate domain classes from the previous example but find an alternative program that does not use polymorphism?
Polymorphism is the combination of substitution and dynamic binding. In step 1 of this example we?ll look at what happens if we use neither substitution nor dynamic binding. In step 2 we?ll use substitution with static binding.

Ex 6.2 step 1 No substitution

Without substitution we need to declare three reference variables in class TfrmSubstitution, to FreeAndNil all three references in the rgbFurnitureClick and btnFreeClick event handlers, and then to test for the existence of all three objects in the btnKindClick event handler.

The association links between classes become much more complex without substitution.
In writing this program without substitution, the only benefit we gain from the inheritance hierarchy is that TFurniture defines a signature, ie the GetKind method, with which TChair and TTable comply.

Ex 6.2 step 2 Substitution without polymorphism

Considering that the previous step was not too successful, can we solve the problem using substitution but not dynamic binding? To do this, remove the dynamic binding in unit FurnitureU (ie revert from the code in example 6.1 step 4 to the code in step 3 by commenting out or removing the virtual and override keywords). Now replace the polymorphic message (example 6.1, step 2, line 37) with a complex If statement to test the class of the current MyFurniture instance and then call the required GetKind method.
32 procedure TfrmSubstitution.btnKindClick(Sender: TObject) ; 33 begin 34   if MyFurniture = nil then 35     lblKind.Caption := 'Object not defined' 36   else if (MyFurniture is TChair) then 37     lblKind.Caption := (MyFurniture as TChair).GetKind 38   else if (MyFurniture is TTable) then 39     lblKind.Caption := (MyFurniture as TTable).GetKind 40   else 41     lblKind.Caption := MyFurniture.GetKind; 42 end; What was accomplished in a single line with polymorphism (step 2 line 37) now requires a complex set of if statements with static binding. We must test explicitly for each possible instance type and then cast it specifically to invoke the correct method. At compile time, the compiler knows that MyFurniture in line 37 must be treated as a TChair because of the typecasting as operator. So in line 37, the MyFurniture object is statically bound to TChair's GetKind method. Similarly in line 39, the compiler has enough information at compile time to bind MyFurniture to TTable's GetKind method. Without any typecasting in line 41, MyFurniture is statically bound to TFurniture's GetKind method because MyFurniture is declared as TFurniture.
To test this, remove the typecasts in lines 37 and 39. You?ll get the TFurniture?s method even with TChair and TTable instances. Alternatively, if you make the wrong typecasts in lines 37 and 39, the static binding will bind to the wrong methods, giving the wrong message:

46 elseif (MyFurniture is TChair) then 37   lblKind.Caption := TTable(MyFurniture).GetKind // wrong typecast 38 else if (MyFurniture is TTable) then 39   lblKind.Caption := TChair(MyFurniture).GetKind // wrong typecast The order of evaluation in the conditional statements is important. If we test first for the class highest in the hierarchy, in this case TFurniture, all the subclasses will also evaluate true because any subclass can substitute for its superclass.
Static binding is slightly faster than dynamic binding. But all the If?ElseIf comparisons introduce their own performance penalty, counteracting the faster static binding, and introduce considerable room for error.

In summary, using static binding introduces a lot of extra coding complexity, makes the program more error prone, makes subsequent enhancement more brittle and generally does not introduce a significant speed advantage.
Source...
Subscribe to our newsletter
Sign up here to get the latest news, updates and special offers delivered directly to your inbox.
You can unsubscribe at any time

Leave A Reply

Your email address will not be published.