Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции програм_new_последняя версия1.doc
Скачиваний:
14
Добавлен:
14.09.2019
Размер:
697.34 Кб
Скачать

Перезагрузка методов.

Четвертая группа методов – перезагружаемые (Overload). Заметим, что и виртуальные и динамические методы могут быть перезагружаемыми. Перезагрузка нужна, чтобы произвести одинаковые или похожие действия с разнотипными данными. Статический метод перекрытия приводит к тому, что потомок «не видит» перекрытый родительский метод и может обращаться к нему только с помощью слова inherited, поэтому в Delphi используется перезагрузка, с помощью которой становятся видны одноименные методы как родителя, так и потомка.

Пример:

Type TFirst=class

i:Extended;

procedure SetData(x:Extended);

end;

TSecond=class(TFirst)

j:Integer;

procedure SetData(AValue:Integer);

end;

. . . . .

var T2:TSecond;

. . . . .

begin

T2.SetData (1.1); (1)

T2.SetData (1); (2)

В этом примере первый вызов метода SetData из объекта T2 с переменной =1.1 (не целая) вызовет ошибку! А второй вызов не приводит к ошибке, т.к. внутри объекта T2 статический метод с параметром типа Extended перекрыт одноименным методом с параметром типа Integer. Компилятор внутри T2 не признает параметр типа Extended.

Для доступа к методу SetData класса TFirst необходимо использовать служебное слово inherited. Например:

procedure TSecond.SetData;

begin

x :=1.1;

inherited SetData (x);

j:=x;

end;

Но нам нужно произвести схожие действия (1), (2) с разнотипными данными в строках одной программы.

Может быть, метод сделать виртуальным?

Нет, нельзя! Поскольку тип и количество параметров в одном и том же виртуальном методе должны в точности совпадать.

Начиная с версии Delphi4 появилась возможность перезагрузить методы (overload), это позволяет видеть одноименные методы как родителя, так и потомка. Чтобы одноименные методы можно было отличить друг от друга, каждый из них должен иметь уникальный набор параметров. В ходе компиляции при обращении к одному из одноименных методов компилятор проверяет тип и количество параметров обращения и на основе этой проверки выбирает нужный метод.

Overload – директива, позволяющая перезагрузить методы:

Type TFirst=class

i:Extended;

procedure SetData(x:Extended); Overload;

end;

TSecond=class(TFirst)

j:Integer;

procedure SetData(AValue:Integer); Overload;

end;

. . . . .

var T2:TSecond;

. . . . .

Теперь в программе можно использовать метод как родителя, так и потомка.

begin

T2.SetData (1.1);

T2.SetData (1);

Можно перезагрузить и виртуальный, и динамический методы. В этом случае надо добавить директиву reintroduce перед директивой overload.

Задача с использованием полиморфизма

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

Пусть определены 3 класса, один из которых является базовым для двух других:

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;

В каждом из этих классов определен метод info. В базовом классе при помощи директивы virtual метод info объявлен виртуальным. Это дает возможность классу–потомку произвести замену виртуального метода своим собственным. В каждом классе–потомке определен свой метод info, который замещает соответствующий метод родительского класса и отмечается директивой override.

Определим метод info для каждого класса индивидуально:

function Tperson.info:string;

begin

result:=’’;

end;

function Tstud.info:string;

begin

result:=fname+' gruppa '+inttostr(fgr);

end;

function Tprof.info:string;

begin

result:=fname+' department '+fdep;

end;

Далее в программе список всех людей можно представить массивом объектов класса Tperson. Отметим, что объект – указатель.

Список людей имеет вид:

list: array[1..szl] of Tperson; { szlразмер списка}

Объявить подобным образом список можно потому, что OP позволяет присвоить указателю на родительский класс значение указателя на класс– потомок. Поэтому элементами массива list могут быть как объекты класса Tstud, так и объекты класса Tprof.

Вывод списка можно осуществить применением метода info к элементам массива, например:

St:= ’’;

for i:=1 to szl do

if list[i]<>nil then

St:=St+list[i].info+#13;

ShowMessage('Spisok:'+#13+St); { вывод в окно сообщения}

Во время работы программы каждый элемент массива может содержать как объект типа Tstud, так и объект типа Tprof.

Концепция полиморфизма обеспечивает применение к объекту именно того метода info, который соответствует типу объекта.

Напишем программу, которая использует объявления классов Tperson, Tstud, Tprof, формирует список студентов и преподавателей и выводит полученный список в окно сообщения. Будем использовать визуальное программирование.

Окно формы будет иметь вид:

GroupBox1—это компонент , объединяющий группу компонентов, связанных по смыслу. В данном случае он включает 2 зависимых переключателя – RadioButton1 и RadioButton2

Текст модуля кода программы:

unit Polimorfizm;

interface

uses

Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

Dialogs, StdCtrls;

Type

TForm1 = class(TForm)

Label1: TLabel;

Label2: TLabel;

Edit1: TEdit;

Edit2: TEdit;

GroupBox1: TGroupBox;

RadioButton1: TRadioButton;

RadioButton2: TRadioButton;

Button1: TButton;

Button2: TButton;

procedure Button1Click(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;

Сonst szl=10;

Var

Form1: TForm1;

list:array[1..szl] of Tperson;

n:integer;

implementation {исполняемая часть}

{$R *.DFM}

constructor Tperson.Сreate(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+' gruppa '+inttostr(fgr);

end;

function Tprof.info:string;

begin

result:=fname+' department '+fdep;

end;

procedure TForm1.Button1Click(Sender: TObject);

//процедура обработки нажатия на кнопку «Добавить»

begin

if n<szl

then

begin

if RadioButton1.Checked

then

list[n]:=Tstud.Create(Edit1.text, StrtoInt(Edit2.text))

else

list[n]:=Tprof.Create(Edit1.text, Edit2.text);

n:=n+1;

end

else

ShowMessage('Spisok zapolnen');

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+#13;

// list[i].info вызовет тот метод info, которому соответствует элемент

ShowMessage('Spisok:'+#13+St);

end;

end.

Процедура TForm1.Button1Click, которая запускается нажатием кнопки «Добавить» создает объект list[n] класса либо Tstud, либо Tprof.

Класс создаваемого объекта определяется состоянием переключателя RadioButton. Установка переключателя в положение Студент определяет класс Tstud, а в положение – Преподаватель определяет класс Tprof. Процедура TForm1.Button2Click, которая запускается нажатием кнопки Список (Button2) применяет метод info к каждому элементу массива list[i] как к объекту списка и формирует строку, представляющую весь итоговый список.

Виртуальность метода info обеспечивает применение к объекту именно того метода info, который соответствует типу объекта.

Отметим, что в данной программе результаты выводятся в окно сообщения процедурой ShowMessage. Например:

Showmessage('Spisok:'+#13+st);

Showmessage('spisok zapolnen');