1. Home
  2. Computing & Technology
  3. Delphi Programming

Introducing Type Inheritance - Delphi OOP Part 6 - Chapter 12
Page 3/3: Statically bound subclass methods; Dynamic binding and polymorphism

By , About.com Guide

Ex 6.1 step 3 Statically bound subclass methods

We want TChair and TTable instances to be able to respond individually about what kind of furniture they are.

unit FurnitureU;

interface

type
   TFurniture = class (TObject)
   public
     function GetKind: string;
   end;

   TChair = class (TFurniture)
   public
     function GetKind: string;
   end;

   TTable = class (TFurniture)
   public
     function GetKind : string;
   end;

implementation

{ TFurniture }

function TFurniture.GetKind: string;
begin
   Result := 'Furniture';
end;

{ TChair }

function TChair.GetKind: string;
begin
   Result := 'A Chair';
end;

{ TTable }

function TTable.GetKind: string;
begin
   Result := 'A Table';
end;

end.
Run and test this. The result is a bit disappointing! No matter whether we click Furniture, Chair or Table we always get the same Furniture message from TFurniture’s GetKind method. So even if the subclasses have their own methods, when they are assigned to the superclass’s variable type, they invoke the superclass’s method and not their own.

Let’s look at this again in terms of the program code. When the compiler reaches line 37 of step 2, the compiler has no way of knowing whether MyFurniture is of type TFurniture, TChair or TTable. The only clue it has is that in step 2 line 16 we declared the Furniture variable to be of type TFurniture.

So when Delphi compiles step 2 line 37, it links the method calls that variable MyFurniture makes to the class TFurniture, irrespective of what class MyFurniture has been assigned to, because this is how the variable Furniture has been declared. This is called early, static or compile-time binding between the variable and the method.

However, this is not what we want. We want Delphi to associate the methods with the class of the particular object we are using at that moment in the execution. If we are using the superclass because the most recent execution of the Case statement caused the execution of step 2 line 26, we want Delphi to call the superclass’s method when it gets to step 2 line 37.

However, if we are using a subclass), we want Delphi to be smart enough to call the appropriate subclass’s method in step 2 line 37. We can achieve this by using late, dynamic or run-time binding. (All three terms refer to the same thing.)

Ex 6.1 step 4 Dynamic binding and polymorphism

We want the subclass methods to be able to override the superclass methods when we are dealing with the subclass. To do this, the superclass must have virtual methods (ie it must use dynamic binding).

Virtual methods are overridden by subclass methods whenever a subclass is substituting for the superclass. We need only change the method declarations to state that the superclass method is a virtual method (ie capable of being overridden) and that the subclass methods are override methods We do not need to change the actual method implementations.


type
   TFurniture = class (TObject)
   public
     function GetKind: string; virtual;
   end;

   TChair = class (TFurniture)
   public
     function GetKind: string; override;
   end;

   TTable = class (TFurniture)
   public
     function GetKind : string; override;
   end;
Run the program and experiment with it to see what it does. Now if you click any RadioButton and then click the Kind button you get the response we were hoping for – the message displays the type of object that was created when you clicked on the RadioButton. At last, the subclass methods are being associated with the subclass instances as they are created at run-time.

So the same statement (step 2 line 37) results in different methods being called, and therefore in different behaviour, depending on the type of the object that is currently assigned to that variable. This is polymorphism, and step 2 line 37 is a polymorphic call.

Two factors are necessary for polymorphism. First, there must be (hierarchical) substitution so that an instance of a subclass can be assigned to a variable of the superclass type. Second, there must be dynamic binding so that the method that is called is determined by the type of the instance at run time. (As mentioned above, static binding is set during compilation. It calls the method determined by the type of the variable declaration unaffected by run time considerations.)

Substitution works only in one direction. If we declare the variable to be of a subclass type, we cannot then substitute a superclass instance. This makes sense: practically, the superclass cannot take on the role of the subclass because the subclass may have additional variables and/or methods not present in the superclass. Semantically it also does not make sense for the superclass to substitute for the subclass. While TTable IsA TFurniture, TFurniture IsNotNecessarilyA TTable: TFurniture cannot act as a TChair because TChair is derived from TFurniture and not the other way around.

That's it for this chapter. Next time we'll take a look at alternatives to polymorphism.

Explore Delphi Programming
About.com Special Features

Reader's Choice Award Winners

What are the best instant messengers, apps, editors and more? You told us, for our 2010 technology awards program. More >

iPad Central

Is Apple's new tablet computer impractical, a must-have -- or both? We'll help you figure it out. More >

  1. Home
  2. Computing & Technology
  3. Delphi Programming
  4. Coding Delphi Applications
  5. OOP in Delphi
  6. Free Online OOP Course
  7. Introducing Type Inheritance - Delphi OOP Part 6 - Chapter 12

©2010 About.com, a part of The New York Times Company.

All rights reserved.