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 TFurnitures GetKind method. So even if the subclasses have their own methods, when they are assigned to the
superclasss variable type, they invoke the superclasss method and not their own.
Lets 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 superclasss 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 subclasss 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.

