Полиморфизм и виртуальные методы
Полиморфизм — это возможность использовать одинаковые имена для методов, входящих в различные классы. Концепция полиморфизма обеспечивает з случае применения метода к объекту использование именно того метода, <оторый соответствует классу объекта.
Пусть определены три класса, один из которых является базовым для двух других:
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 + ' гp.' + 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 к каждому объекту списка (элементу массива), формирует строку, представляющую собой весь список.