Программа на DelphiРефераты >> Программирование и компьютеры >> Программа на Delphi
begin
My1 := TPotomok.Create; {создает класс типа TPredok !}
My2 := TPotomok.Create; {создает класс типа TPotomok}
My1.Value := 'Hello!'; {ошибка, не тот тип поля TPredok}
My2.Value := 'Hello!'; {правильно, работает поле Value: String}
My2.Value := 8; {ошибка: поле Value: Integer перекрыто}
end;
В этом примере описано два класса: TPredok – предок и TPotomok – потомок. Каждый из классов содержит одноименные поля Value разных типов.
Далее в var-секции объявлены две различные переменные My1 и My2 типа class. На первый взгляд может показаться, что оператор-конструктор объекта My1:= TPotomok.Create создаст объект My1 (выделит под него память) типа TPotomok. Однако это не так, поскольку My1 имеет другой тип. По этой причине конструктор создаст объект родительского типа, т. е. объект типа TPredok. Теперь становится понятен источник ошибок, которые имеют место в нескольких операторах приведенного примера.
18.4. Методы класса
Методом класса является инкаспулированная процедура или функция. Эти подрограммы объявляются так же, как обычные подпрограммы. Метод должен быть объявлен в описании класса в виде отдельного заголовка, а код метода – описан в секции implementation с указанием через символ "." принадлежности метода к своему классу, например:
type
TMyClass = class(TObject){объявление класса}
.
procedure DoSomething; {объявление метода DoSomething}
.
end;
Описание для DoSomething должно быть приведено позже в секции implementation модуля:
procedure TMyClass.DoSomething;{вид заголовка класс.метод}
begin
.
end;
При обращении к методу возможно использование составного имени либо оператора With, например:
Var KdnClass: TKdnClass;
…
KdnClass.MyProc1; // два примера обращения к методам
X:= KdnClass.MyFunc2; // с помощью составных имен
…
With KdnClass do // те же обращения
Begin // с помощью оператора With
MyProc1;
X:=MyFunc2;
End;
Одноименные методы могут перекрываться в потомках точно так, как это показано в примере перекрытия полей. Такое перекрытие называется статическим.
Для расширения возможностей чаще используется динамическое перекрытие. Для этого родительский метод должен иметь директиву dinamic (динамический метод) или virtual (виртуальный метод), а перекрывающий метод – директиву override. Пример:
type
TFigure = class
procedure Draw; virtual; {виртуальный метод}
end;
TRectangle = class(TFigure)
procedure Draw; override; {перекрывающий метод}
end;
TEllipse = class(TFigure)
procedure Draw; override; {перекрывающий метод}
end;
В этом примере объявлен виртуальный метод Draw родительского класса TFigure и два одноименных метода в классах-потомках TRectangle и TEllipse. Последние объявлены перекрывающими (override).
Такое объявление позволяет перекрывать методы с целью достижения нужных целей:
var
Figure: TFigure;
begin
Figure := TRectangle.Create; //создание класса
Figure.Draw; // вызов TRectangle.Draw
Figure.Destroy; // уничтожение класса
Figure := TEllipse.Create; //создание класса
Figure.Draw; // вызов TEllipse.Draw
Figure.Destroy; // уничтожение класса
end;
Семантически виртуальный и динамический методы работают одинаково. Разница состоит в том, что виртуальный метод оптимизирует скорость вычислений, а динамический метод оптимизирует размер соответствующего программного кода.
В классе метод может быть объявлен абстрактным с помощью директивы adstract. Такой метод является виртуальным или динамическим, однако, в отличие от других методов, может не иметь в секции implementation своего кода. Класс, имеющий абстрактные методы, называется абстрактным. Такие классы и методы могут ничего не делать, инкаспулируя таким способом доступ к методам потомков, например:
procedure DoSomething; virtual; abstract;
Обращение к неперекрываемому абстрактному методу вызывает ошибку времени выполнения (run time error), например:
Type
TClass2 = class(TClass0)
…
procedure Paint; virtual; abstract;
end;
TClass1 = class(TClass0)
…
procedure Paint; override;
end;
var
jClass1: TClass1;
jClass2: TClass2;
begin
jClass1.Paint; // правильно
jClass2.Paint; // неправильно: обращение к абстрактному методу
…
end;
Каждый класс имеет два особых метода – конструктор и деструктор. Конструктор предназначен для создания класса, т. е. для выделения под него динамической памяти. Деструктор, наоборот, предназначен для уничтожения класса, т. е. для освобождения участка памяти, занятого этим классом. В классе TObject имеются стандартные методы Create (создать) и Destroy (уничтожить). В этом классе объявлен также метод Free, который сначала проверяет корректность адреса и только потом вызывает метод Destroy. В этой связи предпочтительнее использовать метод Free вместо метода Destroy. Всякий класс по умолчанию содержит переменную Self, в которую после выделения динамической памяти помещается адрес класса. Прежде чем выполнить обращение к методам класса, его нужно создать. Хотя конструктор и деструктор являются процедурами, они объявляются специальными словами. Конструктор объявляется словом Constructor, деструктор – словом Destructor. Часто для обеспечения доступа к полям предка в конструкторе необходимо предварительно создать класс-предок. Это можно сделать c помощью слова Inherited.
Пример:
type
TShape = class(TGraphicControl)
Private {внутренние объявления}
FPen: TPen;
FBrush: TBrush;
procedure PenChanged(Sender: TObject);
procedure BrushChanged(Sender: TObject);
public {внешние объявления}
constructor Create(Owner: TComponent); override;
destructor Destroy; override;
.
end;
constructor TShape.Create(Owner: TComponent);
begin
inherited Create(Owner); // создание класса-предка TGraphicControl
Width := 65; // изменение наследуемых свойств TGraphicControl
Height := 65;
FPen := TPen.Create; // создание отдельного поля TPen типа class
FPen.OnChange := PenChanged;
FBrush := TBrush.Create; // создание отдельного поля TBrush типа class
FBrush.OnChange := BrushChanged;
end;
Некоторые простые классы могут быть созданы и уничтожены без объявления конструкторов и деструкторов. Например, если класс является потомком TObject, то в нем явно Constructor и Destructor в некоторых случаях объявлять нет нужды:
Type TClassy = class;