Upload
andrew-schein
View
231
Download
0
Embed Size (px)
DESCRIPTION
12/06/10 1 Основным понятием ООП является объект, который в Delphi представляет собой переменную нового структурированного типа, описываемого с помощью ключевого слова Class. (Объекты всегда распределяются в куче, переменная типа класс это указатель) 2
Citation preview
04/23/23 1
Тема 14. Объекты и классы
Понятие объекта и класса Свойства и методы класса Свойство наследственности Создание, уничтожение и операция
присваивания объектов Понятие полиморфизма Статический, виртуальный и динамический
способы реализации полиморфизма Примеры использования объектов
04/23/23 2
Понятие объекта и класса С появлением языков SmallTalk и C++ в начале 80-х годов
возникла новая методология в технологии программирования – объектно-ориентированное программирование (ООП), основанное на более высоком уровне абстрагирования и модульности. Объекты придумали для упрощения разработки сложных программ и улучшения их качества. В языке Паскаль эта методология появилась, начиная с версии 5.5 (1985 г.).
Основным понятием ООП является объект, который в Delphi представляет собой переменную нового структурированного типа, описываемого с помощью ключевого слова Class. (Объекты всегда распределяются в куче, переменная типа класс это указатель)
Переменная типа Class под одним именем объединяет данные различных типов (поля) и процедуры их обработки (методы)
Объединение данных и процедур их обработки, называемое инкапсуляцией, с приданием ему свойств наследования и полиморфизма оказалось удивительно плодотворным
04/23/23 3
Свойства: - этоМетоды чтения и записи некоторых
полей данных:a, b,…Методы (что умеет)Procedure Fp()Function Ff()
ИмяОбъект Delphi
Обработчики событий:(TForm1.Button1Click)Методы, вызываемые как реакция на событие
Структура объекта
Объектно-ориентированная программа – это совокупность объектов и способов их взаимодействия. Обмен между ними происходит посредством сообщений
поля данных: a, b, x, y, u, v,…
04/23/23 4
• Unit uTob; Описание класса в разделе type • Interface• Type• Tobr=Class(Tobject)• a,b:Typr;• Property ca:Typr read a; //свойство• Function F1(форм.п.F1):T1; // заголовки методов
...• End;// Tobr• Tobp=Class(Tobr)• c,d,e:Typp;• Procedure P1(форм.п.Р1); // методы Tobp• end;// Tobp• Implementation• Function Tobr.F1;• Begin //описание методов• ...... • end;• Procedure Tobp.P1;• begin • ...... • end;• end.// конец uTob Все поля должны иметь разные имена
04/23/23 5
Реализация наследственности Любой класс может быть порожден от другого класса.
Класс Tobp порожден от класса Tobr. Tobr – «класс родитель», а Tobp – «класс-потомок». Порожденный класс (Tobp) автоматически наследует поля и
методы своего родителя (в приведенном примере a, b, F1) и обогащает их новыми (c, d, e, P1).
Принцип наследования позволяет эффективно использовать уже наработанный задел программ и на его основе создавать классы для решения все более сложных задач. Это приводит к тому, что программный продукт представляет собой ветвящееся дерево классов.
Прародителем всех классов в Delphi является класс TObject.
Все компоненты Delphi представляют собой созданные разработчиками классы.
04/23/23 6
Создание, уничтожение объектов• Как всякая динамическая переменная, объект перед началом
работы с ним должен быть создан конструктором класса TObject Create:
• <Имя-переменной-типа-класс> := <тип-класса> . Create;
• После окончания работы с объектом, выделенную под него память необходимо освободить деструктором класса TObject Destroy или Free:
• <Имя-переменной-типа-класс> . Free;
• в состав любого пользовательского класса могут быть введены свои методы Сonstructor и Destructor с дополнительными к Create и Free функциями.
• • Обычно это задание начальных условий совместно c Create или
закрытие файлов перед уничтожением Free.
04/23/23 7
• Unit Unit1; //вызывающая программа• Interface• Implementation• uses uTob; //подключение модуля• Var Obp1,Obp2:Tobp; • Obr1:Tobr // объекты • Begin• ... • Obp1:=Tobp.Create; //создание объекта• Obp1.ca:=10; //полям присвоить значения• Obp1.P1(); //обращение к методу P1• Obp1.Free; //уничтожение объекта• ... • end.//Unit1
04/23/23 8
Понятие свойства класса• Правила хорошего тона при ООП требуют: обращение к полям должно
осуществляться посредством методов.• • Но каждый раз писать имя метода при обращении к полю не всегда
удобно, поэтому придумали специальный механизм, регулирующий доступ к полям.
• Свойство – это специальный механизм класса, регулирующий доступ к полям.
• Свойства объявляются с помощью ключевых слов property… read…write…;
• var p:Tip;• property сp:Tip read методr write методw.
• Свойство связано с некоторым полем и указывает:• методr – метод чтения содержимого поля (функция без параметров)• (например, может сопровождаться выводом на печать)• методw - метод записи в это поле (процедура с одним параметром• имеющим тип свойства).
04/23/23 9
• Пример описания свойства• Type• MyСlass=class( )• pole:byte;• //получить значение p• Function Getpole:byte;• Begin • Getpole:=p; //отразить p на форме• label1.caption:=inttostr(pole);• end;• // присвоить полю значение• Procedure Setpole(p0:byte);• Begin • p:=p0• end; //cp – имя свойства• Property cp:byte read getpole write Setpole;
(Property cp:byte read p;)(Property cp:byte write Setpole;)• ...• end;// MyСlass=class
04/23/23 10
Работа со свойствомVar• Myobj:Myclass;xt:integer;• begin• ....• Myobj:= Myclass.Create;• ...• Myobj.cp:=10;• Myobj.Setpole(10);//это эквивалентно• Myobj.p:=10; // так можно но не рекомендуется • ....• xt:=Myobj.cp;• xt:=Myobj.Getpole;//это эквивалентно• xt:=Myobj.p; //так можно но не рекомендуется• ...• end;
04/23/23 11
Свойства
• Фактически, свойства «живут» только до компиляции программы, во время которой заменяются методами или полями.
• В отличие от полей свойства не занимают места в памяти.
04/23/23 12
операция присваивания Операция присваивания, например, obp2:=obp1;
приводит к копированию только указателя! Переменной родительского типа можно присвоить
значение переменной типа потомка, например, obr1:=obp1.
Обратное же присваивание запрещено. Однако, если переменная родительского типа
указывает на объект, фактически соответствующий переменной типа потомка, то при необходимости ее можно преобразовать к типу потомка с помощью оператора приведения объектных типов as :
obp2:= obr1 as Tobp;
04/23/23 13
Понятие полиморфизма Свойство полиморфизма позволяет использовать одинаковое
название метода для решения сходных но несколько отличающихся у разных родственных классов задач.
Например, метод Add (добавить) имеется у многих компонент
Delphi, хотя в каждой компоненте реализуется по разному.
Обеспечивается это тем, что в классе-потомке метод переписываются по новому алгоритму, т.е. перекрывается. В результате в объекте-родителе и объекте-потомке будут действовать два одноименных метода с разными алгоритмами.
Obp1.Add; Obr1.Add; действуют по разному
Это и называется полиморфизмом объектов.
04/23/23 14
Пример простого перекрытия методов Предположим, что требуется создать пакет
стандартных программ для решения однотипных уравнений (в общем случае задач), которые можно расположить в порядке увеличения сложности и преемственности.
1)ах+b=0; 2)ах2+bx+c=0; 3)и т.п.
Начнем проектирование пакета программ с составления класса-прародителя
04/23/23 15
• Type 1)ах+b=0• Tur1=Class(Tobject)• a,x:array of integer;• n:word;• Lw:TextFile;• procedure Init(no:word;ao,bo:extended);• procedure Solution;• procedure Resultw(FileN:string);• end;• procedure Tur1.Init;• begin n:=no;• SetLength(x,n);setLength(a,n+1)• a[0]:=ao; a[1]:=bo; • end;• procedure Tur1.Solution;• begin• x[0]:=-a[1]/a[0]• end;• procedure Tur1.Resultw;• begin• Assign(Lw,FileN); Rewrite(Lw);• for i:=0 to n do Writel(Lw,a[i]);• for i:=0 to n-1 do Writel(Lw,x[i]);• Close(Lw);• end;
04/23/23 16
Решение 1)ах+b=0• Var Our1:Tur1;• . . .• Begin• Our1:=Tur1.Create;• Our1.Init(1,8,4);• Our1.Solution;• Our1.Resultw(’MySol’);• Our1.Free;• end;
• Результат: a0=8 a1=4 x0=0.5
04/23/23 17
• Класс потомок для ах2+bx+c=0;• Здесь уже достаточно переписать 2 метода• Метод вывода результата будем брать родительский
• Type• Tur2=Class(Tur1)• procedure Init(no:word;ao,bo,co:extended);• procedure Solution;• end;
••
04/23/23 18
• Реализация методов родителя•• procedure Tur2.Init; • begin• Inherited Init(no,ao,bo);• a[2]:=co;• end;• procedure Tur2.Solution;• Var d:extended;• begin• d:=sgrt(sqr(a[1])-4*a[0]*a[2]);• x[0]:=(-a[1]+d)/(2*a[0]);• x[1]:=(-a[1]-d)/(2*a[0]);• end;
•
04/23/23 19
Решение ах2+bx+c=0• Var Our2:Tur2;• .......• Our2:=Tur2.Create;• Our2.Init(2,1.2,5,6.2);• Our2.Solution;• Our2.Resultw(’My Sol’);• Our2.Free;
• Поля данных не перекрываются. Их можно только дополнять в потомках, но не переопределять
04/23/23 20
Если немного модифицировать родительский метод Init
• procedure Init(no:word;• const ao:array of extended);• procedure Tur1.Init;• begin n:=no;• SetLength(x,n);setLength(a,n+1)• for i:=0 to n do a[i]:=ao[i]; • end;
• То надобность перекрытия его в потомке отпадет:• Type• Tur2=Class(Tur1)• procedure Solution;• end;
04/23/23 21
Взаимодействие объекта с методами
При объявлении в разделе var и создании create• Var ur1,up1:Tur1; ur2:Tur2;• ur1:=Tur1.Create;• up1:=Tur1.Create;• ur2:=Tur2.Create; каждый объект располагается по некоторому адресу. Причем все поля данных копируются, методы хранятся в одном экземпляре.
• Может возникнуть вопрос, как при обращении к методу ur1.Solution; ur2.Solution;
• удается определить, с какими полями работать, что делать?• Каждый раз, когда вызывается метод, ему через параметр-
указатель с именем Self, передается адрес того экземпляра объекта, который обращается к методу.
04/23/23 22
Статический, виртуальный и динамический способы реализации полиморфизма
Полиморфизм можно организовать по-разному: используя раннее связывание метода с полями объекта, и позднее связывание.
Статические методы: характеризуются тем, что связывание метода с полями объекта осуществляется во время компиляции (раннее связывание). Предыдущие листинги иллюстрируют статические методы.
Виртуальные и динамические методы: связываются с объектом во время выполнения программы (позднее связывание).
Если метод объявлен виртуальным или динамическим, то нельзя менять типы и число параметров.
Позднее связывание методов позволяет реализовать казалось бы удивительную способность родительского метода использовать методы своих потомков.
04/23/23 23
Реализации позднего связывания • Замещаемый одноименный метод родителя
объявляется как динамический или виртуальный с помощью ключевых словProcedure Ris;dynamic; (или virtual)
• В потомке замещающий метод объявляется директивой
Procedure Ris; override;
• Вызов перекрытого метода родительского класса в одноименном методе потомка достигается с помощью зарезервированного слова
Inherited Ris;(унаследованный).
04/23/23 24
• Interface• Type• Tobr=Class(Tobject)• . . . • Procedure Ris; virtual• End;// Tobr
• Tobp=Class(Tobr)• . . .• Procedure Ris; override; • end;// Tobp• Implementation• . . . • Function Tobp.ris;• Begin• Inherited Ris; //рисуем то что может родитель• ......дорисовываем чего не хватает • end;
Пример организации перекрытия
04/23/23 25
Реализация позднего связывания• Встретив объявления dynamic или virtual, компилятор
создает таблицы соответствия DMT и VMT.• • В этих таблицах помещаются адреса точек входа
методов.
• Таблица VMT “своего” класса хранится в каждом экземпляре объекта в особом, скрытом от программиста поле.
• • Таблица DMT хранится в VMT.• • При каждом обращении к методу компилятор
вставляет в соответствующую таблицу код, позволяющий извлечь затем из нее адрес точки входа в подпрограмму
04/23/23 26
Таблицы VMT DMT Отличие таблиц DMT и VMT в том, что o DMT содержит адреса только тех методов, которые объявлены
как dynamic в данном классеo VMT содержит адреса всех виртуальных методов данного
класса: как нововведенных, так и унаследованных от родителей.
Любой класс имеет VMT, т.к. в Delphi все классы являются потомками класса Tobject, который в свою очередь содержит виртуальные методы.
Более того VMT родителя повторяется в VMT наследника с добавлением в нее сведений о виртуальных методах наследника, если таковые имеются
Использование таблиц VMT обеспечивает более быстрый поиск требуемого метода, но они и занимают много памяти при больших проектах. При использовании динамических методов таблицы DMT создаются только для тех классов, которые их имеют, т.е. они экономят память, но замедляют поиск.
04/23/23 27
Пример абстрактного класса для рисования• Var ColrBack:Tcolor;• Type • Tviz=class(Tobject)• Canvas:Tcanvas;• ColrLine:Tcolor;• x,y,r:word;• Procedure Ris;virtual;abstract;• Procedure Draw(bl:boolean);• procedure Show;• procedure Hide;• procedure MovTo(dx,dy,dr:integer);• end;
• Метод Ris в родительском классе ничего не делает• Объекты абстрактного класса не создаются!
04/23/23 28
Описание методов абстрактного классаПрорисовка рисунка заданным цветом или
цветом фона• Procedure Tviz.Draw(bl:Boolean);• begin• with Canvas do begin• if bl then begin pen.color:=colrLine;• brush.color:=colrLine end• else begin pen.color:=colrBack;• brush.color:=colrBack end;• ris; //процедура ris что-то рисует• end;•
04/23/23 29
Описание методов абстрактного класса• Procedure Tviz.Show; (показать рисунок)• begin• Draw(true);• end;• Procedure Tviz.Hide; (стереть рисунок)• begin• Draw(false)• end;• procedure Tviz.MovTo; (передвинуть рис)• begin• Hide;• x:=x+dx; y:=y+dy; r:=r+dr;• Show;• end;
04/23/23 30
Класс потомок рисования круга• Unit unit2;• interface• uses Graphics;• var ColrBack:Tcolor;• Type• Tviz=class(Tobject)• <Вставить описание которое приведено выше>• end;• TKrug=class(Tviz)• x1,y1,x2,y2:word;• Constructor Create(x0,y0,r0:word;• colrLine0:Tcolor;canvas0:Tcanvas);• Procedure Ris; override;• end;• . . .
04/23/23 31
Класс потомок рисования круга• implementation• <Описание методов Tviz>• Constructor TKrug.Create;• begin• colrLine:=colrLine0;• canvas:=canvas0;• x:=x0; y:=y0; r:=r0;• end;• Procedure Tkrug.ris;• Begin• x1:=x-r; x2:=x+r; y1:=y-r; y2:=y+r;• Canvas.Ellipse(x1,y1,x2,y2);• end; • End.
04/23/23 32
Программа рисования• unit Unit1;• interface• uses• Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, StdCtrls;
• type• TForm1 = class(TForm)• Button1: TButton;• Image1:TImage;• . . . . . . . . . • procedure Button1Click(Sender: TObject);• . . . . . . . . . • end;• var• Form1: TForm1;• implementation• uses unit2, Clipbrd;
04/23/23 33
• var krug:Tkrug; Программа рисования• okno1:Timage;• pxm1,pym1:word;• xo,yo,ro:word;• procedure TForm1.Button1Click(Sender: TObject);• begin• okno1:=Form1.Image1;• colrBack:=clWhite;• pxm1:=okno1.ClientWidth;• pym1:=okno1.ClientHeight;• with okno1.canvas do begin• pen.color:=colrBack;• brush.color:=colrBack;• Rectangle(0,0,Pxm1,Pym1);• end;• xo:=pxm1 div 2; yo:=pym1 div 2; ro:=10;• Krug:=Tkrug.Create(xo,yo,ro,clBlack,okno1.canvas);• krug.Show; • End;
04/23/23 34
Перемещения круга• procedure TForm1.Button2Click(Sender: TObject);• begin //Увеличить круг• Krug.MovTo(0,0,3);• end;• procedure TForm1.Button3Click(Sender: TObject);• begin //уменьшить• Krug.MovTo(0,0,-3);• end;• procedure TForm1.Button4Click(Sender: TObject);• begin //двигать вправо-вверх• Krug.MovTo(3,3,0);• end;• procedure TForm1.Button5Click(Sender: TObject);• begin //двигать влево-вниз• Krug.MovTo(-3,-3,0);• end;
04/23/23 35
Печать картинки и уничтожение объекта
• procedure TForm3.Button8Click(Sender: TObject);• begin //только для TImage !!! сохранить
картинку• Clipboard.Assign(Image1.Picture);• end;• procedure TForm1.BitBtn6Click(Sender: TObject);• begin• krug.Free;• end;
04/23/23 36
Круг+прямоугольник (тело)• Interfase• TKrPr=class(Tkrug)• dy1:word;• Constructor Create(x0,y0,r0,dy0:word; • colrLine0:Tcolor;canvas0:Tcanvas);• Procedure ris; override;• end;• Implementation• Constructor TKrPr.create;• begin• dy1:=dy0;• Inherited Create(x0,y0,r0,colrLine0,canvas0);;• end;• Procedure TkrPr.ris;• begin• Inherited ris;• Canvas.Rectangle(x1,y2,x2,y2+dy1);• end;
04/23/23 37
Движение тела
Создадим:Krpr:= Tkrpr.Create(xo,yo,ro,4*ro,clBlack,okno1.canvas); Krpr.show;Двигаем:
• procedure TForm3.Button6Click();• begin• //ход конем• krpr.MovTo(10,0,0);• okno1.Update;• sleep(200);• krpr.MovTo(0,5,0);• end;
04/23/23 38
Демонстрация конец