Last Updated:

Polymorphism | Delphi | Tutorial

Consider the following example carefully. Suppose we have some generalized field for storing data - the TFieid class and its three descendants - for storing strings, integers and real numbers:

type
TField = class
function GetData:string; virtual; abstract;
end;
TStringFieid = class(TField)
FData: string;
function GetData: string; override;
end;
TIntegerField = class(TField)
FData: Integer;
function GetData: string;override;
end;
TExtendedField = class(TField)
FData: Extended;
function GetData: string;override;
end;
function TStringFieid.GetData;
begin
Result: = FData
end;
function TIntegerField.GetData;
begin
Result: = IntToStr(FData);
end;
function TExtendedField.GetData;
begin
Result: = FloatToStrF(FData, ffFixed, 7, 2);
end;
procedure ShowData(AField: TField);
begin
Forml.Label!.Caption: = AField.GetData;
end;

In this example, the classes contain different FData data fields and only know how to communicate the value of that data with a text string (using the GetData method). An external ShowData procedure receives an object as a parameter and displays that string.

Object Pascal's typecasting rules state that an object, as a pointer to an instance of an object type, can be assigned the address of any instance of any of the child types. In the showData procedure, the parameter is described as TFieid, which means that you can pass objects of classes TStringFieldTIntegerFieldTExtendedField, and any other descendant of the TFieid class to it.

But which (or rather, whose) GetData method will be called? The one that corresponds to the class of the actually transferred object. This principle is called polymorphism, and it represents perhaps the most important trump card of the PLO.

Let's say you are dealing with some set of phenomena or processes. To model them by means of OOP, it is necessary to highlight their most common, typical features. Those that do not change their content should be implemented in the form of static methods. Those that change during the transition from the general to the particular, it is better to dress up in the form of virtual methods.

Basic, "generic" traits (methods) should be described in the ancestor class and then overlap them in the descendant classes. In our example, what matters to a programmer writing a procedure like showData is that any object passed to it is a child of TFieid and is able to report the value of his data (by executing the GetData method). If, for example, such a procedure is compiled and placed in a dynamic library, then this library can be used once and for all without modification, although new, unknown at the time of its creation, descendant classes of TFieid will appear.

An illustrative example of the use of polymorphism is given by the Delphi environment. It has a TComponent class, at the level of which certain "rules" for the interaction of components with the development environment and with other components are concentrated. By following these rules, you can derive your components from the TComponent class, configuring Delphi to solve special problems.

Now, hopefully, it's become more or less clear what advantages OOP has allowed it to become the primary way to develop serious software. Those who started programming for Windows 3.0 probably remember how much effort it took to write completely trivial code. Now for the same in Delphi, just a couple of mouse clicks are enough. In fact, it was the complexity of programming for Windows that became the catalyst for the introduction of OOP.