Связь и интернет Архив Программирование
   
Сделать стартовойСделать закладку            
   ПОИСК  
   
Главная / Pascal и Delphi / Иллюстрированный самоучитель по Delphi 6 / Часть II . Язык Object Pascal / Классы и интерфейсы /
8  Perl
8  PHP
8  JavaScript
8  HTML
8  DHTML
8  XML
8  CSS
8  C / C++
8  Pascal и Delphi
8  Турбо Ассемблер
8  MySQL
8  CASE-технологии
8  Алгоритмы
8  Python
8  Обратная связь
8  Гостевая книга
Новости о мире


Составляющие класса - Программирование от RIN.RU
Составляющие класса




Поля


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


type
TMyClass = class
aIntField: Integer;
aStrField: String;
aObjField: TObject;
end;


Каждый объект получает уникальный набор полей, но общий для всех объектов данного класса набор методов и свойств. Фундаментальный принцип инкапсуляции требует обращаться к полям только с помощью методов и свойств класса. Однако в Object Pascal разрешается обращаться к полям и напрямую:


type
TMyClass = class
FIntField: Integer;
FStrField: String;
end;
var
aObject: TMyClass;
begin
aObject.FIntField := 0;
aObject.FStrField := 'Строка символов';
end;


Класс-потомок получает все поля всех своих предков и может дополнять их своими, но он не может переопределять их или удалять.


Таким образом, чем ниже в дереве иерархии располагается класс, тем больше данных получают в свое распоряжение его объекты.


Методы


Инкапсулированные в классе процедуры и функции называются методами. Они объявляются так же, как и обычные подпрограммы:


type
TMyClass = class
Function MyFunc(aPar: Integer): Integer;
Procedure MyProc;
end;


Доступ к методам класса, как и к его полям, возможен с помощью составных имен:


var
aObject: TMyClass;
begin
aObject.MyProc;
end;


Как уже говорилось, методы класса могут перекрываться в потомках. Например:


type
TParentClass = class Procedure DoWork;
end;
TChildClass = class(TParentClass) Procedure DoWork;
end;


Потомки обоих классов могут выполнять сходную по названию процедуру DoWork, но, в общем случае, будут это делать по-разному. Такое замещение методов называется статическим, т. к. реализуется компилятором.


В Object Pascal гораздо чаще используется динамическое замещение методов на этапе прогона программы. Для реализации этого метод, замещаемый в родительском классе, должен объявляться как динамический (с директивой dynamic) или виртуальный (virtual). Встретив такое объявление, компилятор создаст две таблицы -DMT (Dynamic Method Table) и VMT (Virtual Method Table) и поместит в них адреса точек входа соответственно динамических и виртуальных методов. При каждом обращении к замещаемому методу компилятор вставляет код, позволяющий извлечь адрес точки входа в подпрограмму из той или иной таблицы. В классе-потомке замещающий метод объявляется с директивой override (перекрыть). Получив это указание, компилятор создаст код, который на этапе прогона программы поместит в родительскую таблицу точку входа метода класса-потомка, что позволит родителю выполнить нужное действие с помощью нового метода.


Пусть, например, родительский класс с помощью методов show и Hide соответственно показывает что-то на экране или прячет изображение. Для создания изображения он использует метод Draw с логическим параметром:


type
TVisualObject = class(TWinControl)
Procedure Hide;
Procedure Show;
Procedure Draw(IsShow: Boolean); virtual;
end;


TVisualChildObject = class(TVisualObject)
Procedure Draw(IsShow: Boolean); override;
end;


Реализация методов show и Hide очень проста:


Procedure TVisualObject.Show;
begin
Draw(True) ;
end;


Procedure TVisualObject.Hide;
begin
Draw(False) ;
end;


Методы Draw у родителя и потомка имеют разную реализацию и создают разные изображения. В результате родительские методы show и Hide - прятать или показывать те или иные изображения будут в зависимости от конкретной реализации метода Draw у-любого из своих потомков. Динамическое связывание в полной мере реализует полиморфизм классов.


Разница между динамическими и виртуальными методами состоит в том, что таблица динамических методов DMT содержит адреса только -тех методов, которые объявлены как dynamic в данном классе, в то время как таблица VMT содержит адреса виртуальных методов не только данного класса, но и всех его родителей. Значительно большая по размеру таблица VMT обеспечивает более быстрый поиск, в то время как при обращении к динамическому методу программа сначала просматривает таблицу DMT у объекта, затем -у его родительского класса и так далее, пока не будет найдена нужная точка входа.


Динамически перекрываемые методы часто могут вообще ничего не делать. Такие методы называются абстрактными, они обязаны перекрываться в потомках. Программист может запретить вызов абстрактного метода, объявив его с директивой abstract. Например:


type
TVisualObject = class(TWinControl)
Procedure Draw(IsShow: Boolean); virtual; abstract;
end;


TVisualChildObject = class(TWinControl)
Procedure Draw(IsShow: Boolean); override; end;
var
aVisualObject: TVisualObject;
aVisualChild: TVisualChildObject ;
begin
aVisualObject.Show; {Ошибка/ Обращение к абстрактному методу}
aVisualChild.Show;
{Нормальное обращение. Метод Draw у класса TVisualChildObject перекрыт.)
end;


Обращение к неперекрытому абстрактному методу вызывает ошибку периода исполнения. Разумеется, в грамотно составленной программе абстрактные методы никогда не вызываются. Классы, содержащие абстрактные методы, называются абстрактными. Такие классы инкапсулируют общие свойства своих неабстрактных потомков, но объекты абстрактных классов никогда не создаются и не используются. Для эксплуатации абстрактных классов в библиотеку классов Delphi включаются классы-потомки, в которых перекрываются абстрактные методы родителя.


В состав любого класса входят два специальных метода -конструктор и деструктор. У класса TObject эти методы называются create и Destroy, так же они называются в подавляющем большинстве его потомков. Конструктор распределяет объект в динамической памяти и помещает адрес этой памяти в переменную self, которая автоматически объявляется в классе. Деструктор удаляет объект из кучи. Обращение к конструктору должно предварять любое обращение к полям и некоторым методам объекта. По своей форме конструкторы и деструкторы являются процедурами, но объявляются с помощью зарезервированных слов constructor и Destructor:


type
TMyClass = class
IntField: Integer;
Constructor Create(Value: Integer);
Destructor Destroy;
end;


Любые поля объекта, а также методы класса, оперирующие с его полями, могут вызываться только после создания объекта с помощью вызова конструктора, т. к. конструкторы распределяют объект в динамической памяти и делают действительным содержащийся в объекте указатель.


var
MyObject: TMyClass;


begin
MyObject.IntField := 0;
{ Ошибка! Объект не созданконструктором!}
MyObject := TMyClass.Create;
// Надо так: создаем объект
MyObject.IntField := 0;
// и обращаемся к его полю
MyObect.Free;
// Уничтожаем ненужный объект
end;


В базовом классе TObject определен метод Free, который сначала проверяет действительность адреса объекта и лишь затем вызывает деструктор Destroy. Обращение к деструктору объекта будет ошибочным, если объект не создан конструктором, поэтому для уничтожения ненужного объекта следует вызывать метод Free, как это сделано в предыдущем примере.


Большинство конструкторов реализуют некоторые действия, необходимые для правильной работы объекта. Поэтому в конструкторе класса-потомка следует сначала вызвать конструктор своего родителя, а уже затем осуществлять дополнительные действия. Вызов любого метода родительского класса достигается с помощью зарезервированного слова inherited (унаследованный):


Constructor TMyClass.Create(Value: Integer);
// Возможная реализация конструктора
begin
Inherited Create; // Вызываем унаследованный конструктор IntField := Value; // Реализуем дополнительные действия
end;


Некоторые методы могут вызываться без создания и инициации объекта. Такие методы называются методами класса, они объявляются с помощью зарезервированного слова class:


type
TMyClass = class(TObject)
class Function GetClassName: String;
end;
var
S: String;


begin
S := TMyClass.GetClassName;
end;


Методы класса не должны обращаться к полям, т. к. в общем случае вызываются без создания объекта, а следовательно, в момент вызова полей просто не существует. Обычно они возвращают служебную информацию о классе - имя класса, имя его родительского класса, адрес метода и т. п.


Вперед  >>>
 1  2  3 


 8  Комментарии к статье  8 8  Обсудить в чате

 
  
  
    Copyright ©  RIN 2003 - 2004      * Обратная связь