Поліморфізм і віртуальні методи

Поліморфізм – це можливість використовувати однакові імена для методів, що входять в різні класи. концепція поліморфізму забезпечує з разі застосування методу до об’єкта використання саме того методу,  який відповідає класу об’єкта.

Нехай визначені три класу, один з яких є базовим для двох інших:

tуре
// базовий клас TPerson = class
fname: string; // ім'я
constructor Create (name : string);
function info: string;

virtual;

end;
// похідний від TPerson TStud = class (TPerson)
fgr: integer; // номер навчальної трупи
constructor Create (name: string; gr: integer);
function info: string; override; end;
// похідний від TPerson TProf = class (TPerson)
fdep: string; // назва кафедри
constructor Create (name : string; dep: string);
function info: string;

override;

end;

У кожному з цих класів визначено метод info. У базовому класі за допомогою директиви virtual метод info оголошений віртуальним. Оголошення методу віртуальним дає можливість дочірньому класу зробити заміну віртуального методу своїм власним. У кожному дочірньому класі визначений свій метод info, який заміщає відповідний метод батьківського класу (метод породженого класу, що заміщає віртуальний метод батьківського класу, позначається директивою override).

Нижче наведено визначення методу info для кожного класу.

function TPerson.info: string;

begin
result : = '';

end;
function TStud.info: string;

begin
result : = Fname + 'гр.' + IntTostr (fgr);

end;
function TProf.info:string;

begin
result : = Fname + 'каф.' + Fdep;

end;

Так як обидва класу породжені від одного і того ж базового, оголосити список студентів і викладачів можна так (тут слід згадати, що об’єкт – це покажчик):

list: array [l . .SZL] of TPerson;

Оголосити подібним чином список можна тому, що мова Delphi дозволяє вказівником на батьківський клас привласнити значення покажчика на дочірній клас. Тому елементами масиву list можуть бути як об’єкти класу TStud, так і об’єкти класу TProf.
Вивести список студентів і викладачів можна застосуванням методу info до елементів масиву. наприклад, так:

st : = '';
for i: = l to SZL do // SZL - розмір масиву-списку

if list [i] про NIL
then st: = st + list [i] .Info

+ # 13; ShowMessage (st);

Під час роботи програми кожен елемент масиву може містити як об’єкт типу xstud, так і об’єкт типу TProf. Концепція поліморфізму забезпечує застосування до об’єкту саме того методу, який відповідає типу об’єкта.
Наступна програма, використовуючи розглянуті вище оголошення класів TPerson, TStud і TProf, формує і виводить список студентів і викладачів. Текст програми приведений в лістингу 9.1, а діалогове вікно – на рис. 9.1.

Рис. 9.1. Діалогове вікно програми Поліморфізм

Лістинг 9.1. демонстрація поліморфізму

unit polimor_;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = Class (TForm) Edit1: TEdit;

Edit2: TEdit;

GroupBoxl: TGroupBox;

RadioButton1: TRadioButton;

RadioButton2: TRadioButton;

Label1: TLabel;

Label2: TLabel;

Button1: TButton;
Button2: TButton;
procedure ButtonlClick (Sender: TObject);
procedure Button2Click (Sender: TObject);
private
{ Private declarations}

public
{ Public declarations}

end;

type
// базовий клас
TPerson = class
fName: string; // ім'я

constructor Create (name : string);

function info: string; virtual;
end;
// клас Студент TStud = class (TPerson)
fGr: integer; // номер групи
constructor Create (name: string; gr: integer);
function info: string;

override;

end;
// клас Викладач
TProf = class (TPerson)
fdep: string; // назва кафедри

constructor Create (name : string; dep: string);

function info: string;

override;
end;
const
SZL = 10; // розмір списку
var
Forml: TForm1;
List: array [l..SZL] of TPerson; // список
n: integer = 0; // кількість людей в списку
implementation
{$ R * .DFM}
constructor TPerson.Create (name: string) ;

begin
fName : = Name; end;
constructor TStud.Create (name: string; gr: integer) ;

begin
inherited create (name); // викликати конструктор базового класу
fGr : = Gr; end;
constructor TProf.create (name: string; dep: string);

begin
inherited create (name); // викликати конструктор базового класу
fDep : = Dep; end;
function TPerson.Info : string;

begin
result : = Fname; end;
function TStud.Info:string;

begin
result : = Fname + 'rp.' + IntToStr (fGr); end;
function TProf.Info:string;

begin
result : = Fname + 'каф.' + FDep;

end;
// клацання на кнопці Додати
procedure TForml.ButtonlClick (Sender: TObject);

begin
if n < SZL then begin
// додати об'єкт до списку

n: = n + l;

if Radiobuttonl.Checked
then // створимо об'єкт TStud
List [n]: = TStud.Create (Edit1.Text, StrToInt (Edit2.Text ))

else // створити об'єкт TProf
List [n]: = TProf.Create (Edit1.Text, Edit2.Text); // очистити поля введення

Edit1.Text : = ''; Edit2.Text: = '';
Edit1.SetFocus; // курсор в поле Прізвище

end
else ShowMessage ( 'Список заповнений!');

end;
// клацання на кнопці Список
procedure TForm1.Button2Click (Sender: TObject);
var
i: integer; // індекс

st: string; // список begin
for i: = 1 to SZL do
if list [i] <> NIL then st: = st + list [i] .info + 113;
ShowMessage ( 'Cпіcoк' + # 13 + st); end;
end.

Процедура TForml.Buttoniciick, яка запускається натисканням кнопки Додати (Buttonl), створює об’єкт iist [n] класу TStud або TProf. Клас створюваного об’єкту визначається станом перемикача RadioButton. Установка перемикача в положення студент (RadioButtoni) визначає клас TStud, а в положення викладач (RadioButton2) – клас TProf.
Процедура TForm1.Button2Сlick, яка запускається натисканням кнопки Список (Button2), застосовуючи метод info до кожного об’єкту списку (елементу масиву), формує рядок, що представляє собою весь список.