Читайте также:
|
|
Объект "появляется на свет" в результате вызова специального метода, который инициализирует объект — конструктора. Созданный экземпляр уничтожается другим методом — деструктором:
AMyObject:= TMyObject.Create;
{ действия с созданным объектом }
AMyObj ect.Destroy;
В Object Pascal конструкторов у класса может быть несколько. Общепринято называть конструктор create (в отличие от Borland Pascal 7.0, где конструктор обычно назывался Init, и от C++, где его имя совпадает с именем класса). Типичное название деструктора — Destroy.
type
TMyObject = class(TObject)
MyField: Integer;
Constructor Create;
Destructor Destroy;
Function MyMethod: Integer;
end;
Для уничтожения экземпляра объекта рекомендуется использовать метод Free, который первоначально проверяет указатель (не равен ли он nil) и только затем вызывает Destroy:
AMyObject.Free;
До передачи управления телу конструктора происходит собственно создание объекта — под него отводится память, значения всех полей обнуляются. Далее выполняется код конструктора, написанный программистом для инициализации экземпляров данного класса. Таким образом, хотя на первый взгляд синтаксис конструктора схож с вызовом процедуры (не определено возвращаемое значение), но на самом деле конструктор — это функция, возвращающая созданный и проинициализированный объект.
Конструктор создает новый экземпляр объекта только в том случае, если перед его именем указано имя класса. Если указать имя уже существующего объекта, он поведет себя по-другому: не создаст новый экземпляр, а только выполнит код, содержащийся в теле конструктора.
Чтобы правильно проинициализировать в создаваемом объекте поля, относящиеся к классу-предку, нужно сразу же при входе в конструктор вызвать конструктор предка при помощи зарезервированного слова
inherited:
constructor TMyObject.Create;
begin inherited Create;
end;
Что же касается объектов, создаваемых вами динамически (во время выполнения приложения), то здесь нужен явный вызов конструктора и метода Free.
7. Инкапсуляция.
Инкапсуляция (encapsulation) - это механизм, который объединяет данные и код, манипулирующий зтими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создаётся так называемый "чёрный ящик". Когда коды и данные объединяются таким способом, создаётся объект (object). Другими словами, объект - это то, что поддерживает инкапсуляцию.
Внутри объекта коды и данные могут быть закрытыми (private). Закрытые коды или данные доступны только для других частей этого объекта. Таким образом, закрытые коды и данные недоступны для тех частей программы, которые существуют вне объекта. Если коды и данные являются открытыми, то, несмотря на то, что они заданы внутри объекта, они доступны и для других частей программы. Характерной является ситуация, когда открытая часть объекта используется для того, чтобы обеспечить контролируемый интерфейс закрытых элементов объекта.
На самом деле объект является переменной определённого пользователем типа. Может показаться странным, что объект, который объединяет коды и данные, можно рассматривать как переменную. Однако применительно к объектно-ориентированному программированию это именно так. Каждый элемент данных такого типа является составной переменной.
8. Инкапсуляция и модули
Модули также могут использоваться для инкапсуляции.
9. Директивы видимости
Все что объявлено в секции private, доступно только внутри модуля в котором объявлен класс (приватные объявления). Здесь как правило объявляются переменные, в которых хранятся значения свойств, а также методы (процедуры или функции) доступа к ним.
Все что объявлено в секции protected, доступно как и в секции private, а также наследникам данного класса (интерфейс разработчика). Здесь можно объявить методы доступа к значениям свойств (если вы хотите позволить изменять эти методы потомкам вашего компенента), а также свойства, методы и события (методы реакции на события) в компонентах типа TCustomXXX.
Все что объявлено в секции public, доступно любому пользователю компонента (интерфейс этапа выполнения). Здесь объявляются, как правило методы.
В секции published можно объявлять только свойства и события (они объявляются в виде свойств). Они доступны во время проектирования приложения (интерфейс этапа проектирования).
10. Инкапсуляция и свойства.
Классическое правило объектно-ориентированного программирования утверждает, что для обеспечения надежности нежелателен прямой доступ к полям объекта: чтение и обновление их содержимого должно производиться посредством вызова соответствующих методов. Это правило и называется инкапсуляцией. В старых реализациях ООП (например, в Turbo Pascal) эта мысль внедрялась только посредством призывов и примеров в документации: в языке же Object Pascal есть соответствующая конструкция. В Delphi пользователь вашего объекта может быть полностью отгорожен от полей при помощи свойств.
Обычно свойство определяется тремя элементами: полем и двумя методами, которые осуществляют его чтение/запись:
TAnObject = class(TObject)
function GetAProperty: TSomeType;
procedure SetAProperty(ANewValue: TSomeType);
property AProperty: TSomeType read GetAProperty write SetAProperty;
end;
В данном примере доступ к значению свойства AProperty осуществляется через вызовы методов GetAProperty и SetAProperty.
11. Свойства-массивы.
Некоторые свойства могут использовать не одно, а множество значений. Например, таковым является свойство Lines компонента ТМето, значением которого является множество строк. Обращение к конкретному значению свойства-массива осуществляется по индексу:
Memol.Lines[0]:= 'Строка';
Свойства-массивы имеют перечисленные ниже особенности.
• Свойства-массивы объявляются с указанием одного или нескольких индексных параметров. Тип индексов должен быть целым или строковым (в отличие от обычных массивов, свойства-массивы могут индексироваться строками).
• Доступ к значению свойства-массива может быть только косвенным (через методы SetXXXX/GetXXXX).
• Если в определении свойства-массива используется несколько индексов (многомерные свойства-массивы), методы доступа должны содержать параметры для каждого индекса в том же порядке, что и в объявлении свойства.
• Свойства-массивы нельзя объявлять в секции published. Доступ к значениям свойства-массива на этапе конструирования возможен только с помощью специализированного редактора свойств.
В качестве примера создадим класс TPlanets, который хранит названия всех планет Солнечной системы (листинг 7.1).
Листинг 7.1. Класс TPlanets, иллюстрирующий особенности свойств-массивов Unit Planets;
interface
uses
Classes, SysUtils; type
TPlanets = class(TComponent) private
// Методы доступа к свойству-массиву
function GetPlan^tName(const AIndex: Integer): String; function GetPlanetPosition(const AName: String): Integer; public
// Свойства-массивы нельзя публиковать!
// Следующее свойство возвращает название планеты по ее номеру property PlanetName[const AIndex: Integer]: String
read GetPlanetName; default; // Следующее свойство возвращает номер планеты по ее названию property PlanetPosition[const AName: String]: Integer
read GetPlanetPosition;
end; implementation const
PlanetNames: array [1..9] of String[8] = ('Меркурий1, 'Венера1, 'Земля', 'Марс', 'Юпитер', 'Сатурн', 'Нептун', 'Уран', 'Плутон');
12. Индексируемые свойства.
Индексированные свойства определяются с помощью зарезервированного слова index. Например:
type
TSampleCalendar = plass(TCustomGrid) public
property Day: Integer index 3 read GetDateElement write SetDateElement;
property Month: Integer index 2 read GetDateElement write SetDateElement;
property Year: Integer index 1 read GetDateElement write SetDateElement; private
FDate: TDateTime;
function GetDateElement(Index: Integer): Integer; procedure SetDateElement(Index: Integer; Value: Integers-end;
Как видите, все три индексированные свойства используют одинаковые методы доступа, но передают им разные индексы. Это позволяет методам определить, о каком элементе даты идет речь, и произвести соответствующие действия. Индексированными можно объявлять только свойства одного и того же типа. Они позволяют экономить память: если бы свойства не были индексированы, нам пришлось бы писать пару почти одинаковых методов GetXXXX/SetXXXX для каждого свойства.
13. Свойства и иерархия классов
Благодаря механизму наследования свойств и методов, потомки базовых классов умеют "общаться" друг с другом; работают в среде разработки, взаимодействуя с Палитрой компонентов и Инспектором объектов; распознаются операционной системой как элементы управления и окна.
В основе иерархии классов лежит класс TObject. Он обеспечивает выполнение важнейших функций "жизнедеятельности" любого объекта. Благодаря ему, каждый класс получает в наследство механизмы создания экземпляра объекта и его уничтожения.
Обычно разработчик даже не задумывается о том, как объект будет создан и что необходимо сделать для его корректного уничтожения. Компоненты VCL создаются и освобождают занимаемые ресурсы автоматически. Иногда разработчику приходится создавать и удалять объекты самостоятельно. Но даже в этом случае ему достаточно вызвать соответствующие конструктор и деструктор:
var SomeList: TStrings;
...
SomeList:= TStrings.Create;
...
SomeList.Free;
За кажущейся простотой этих операций скрывается довольно сложная реализация указанных процессов. Практически весь исходный код класса TObject написан на ассемблере для обеспечения наибольшей эффективности операций, которые будут выполняться в каждом его потомке.
Кроме этого, класс TObject обеспечивает создание и хранение информации об экземпляре объекта и обслуживание очереди сообщений.
Класс TPersistent происходит непосредственно от класса TObject. Он обеспечивает своих потомков возможностью взаимодействовать с другими объектами и процессами на уровне данных. Его методы позволяют передавать данные в потоки, а также обеспечивают взаимодействие объекта с Инспектором объектов.
Класс TComponent является важнейшим для всех компонентов. Непосредственно от него можно создавать любые невизуальные компоненты. Механизмы, реализованные в классе TComponent, обеспечивают взаимодействие компонента со средой разработки, главным образом с Палитрой компонентов и Инспектором объектов. Благодаря возможностям этого класса, компоненты начинают работать на форме проекта уже на этапе разработки.
Класс TControl происходит от класса TComponent. Его основное назначение — обеспечить функционирование визуальных компонентов. Каждый визуальный компонент, произошедший от TControl, наделяется основными признаками элемента управления. Благодаря этому, каждый визуальный компонент умеет работать с GUI (Graphic User Interface — графический интерфейс пользователя ОС) и отображать себя на экране.
Класс TWinControl расширяет возможности разработчиков по созданию элементов управления. Он наследуется от класса TControl и обеспечивает создание оконных элементов управления.
На основе класса TWinControl создан еще один дополнительный класс — TCustomControl. Он обеспечивает создаваемые на его основе компоненты возможностями по использованию канвы — специального объекта, предназначенного для отображения графики (подробнее о канве см. гл. Л).
Класс TCustomControl является общим предком для целой группы классов, обеспечивающих создание различных нестандартных типов оконных (получающих фокус) элементов управления Windows: редакторов, списков и т. д.
Для создания неоконных (не получающих фокус) элементов управления используется класс TGraphicControl, являющийся потомком класса TControli.
В целом иерархия базовых классов обеспечивает полноценную работу разработчиков в Delphi, позволяя проектировать любые типы приложений.
14. Конструкторы, перегрузка конструкторов
Ключевое слово Constructor определяет процедуру Name конструктора для класса.
При создании объекта, вы вызываете метод Constructor класса, а не объекта:
objectName:= ClassName.Create(parms);
Название (Name) для конструктора, обычно Create, но оно этим не ограничено. Однока, будет мудро сохранить это название.
Объект может быть создан с или без параметров (см. пример).
Конструкторы могут быть определены в public или published разделах определения класса.
Вы можете иметь множество конструкторов, но при этом, вы можете определить только один из них как Published. При многочисленных конструкторах, к каждому должна быть прибавлена директива Overload.
При осуществлении процедуры конструктора, обычно называемой Create, вы должны вызвать родительского конструктора и сделать это привычкой, например
constructor Create;
inherited;
...
Это гарантирует, что конечный объект безопасно проиллюстрирует образец этого родительского класса, даже если родитель TObject, который не делает ничего в его конструкторе. Код примера иллюстрирует это простое разнообразие Inherited плюс версию, где родительский конструктор имеет параметры.
15. Деструкторы.
Деструктор – это специальная разновидность подпрограммы, присоединенной к классу. Его назначение заключается в уничтожении экземпляра класса, т.е. объекта и освобождении памяти, выделенной под экземпляр. Деструктор уничтожает экземпляр класса, который был использован при его вызове, автоматически освобождая любую динамическую память, которая ранее была зарезервирована конструктором, закрывает файлы и т.п. операции. Программист ответственен за вызов деструкторов для всех экземпляров класса, если были зарезервированы подчиненные объекты.
Синтаксис реализации деструктора:
Destructor <имя класса>.<имя деструктора>[(<параметры>)];
[<блок объявлений>]
Begin
<исполняемые операторы>
End;
Реализация наследуемых деструкторов
Если использовать механизм наследования деструкторов, то можно упростить задачу уничтожения экземпляров класса, таким образом, чтобы каждый раз заботиться лишь об уничтожении тех полей, которые были добавлены в данном классе. Всю работу по очистке наследуемых полей можно возложить на наследуемые деструкторы. Для вызова наследуемого деструктора необходимо используется ключевое слово Inherited.
Синтаксис объявления наследуемого деструктора следующий:
Destructor <имя класса>.<имя деструктора>[(<параметры>)};
[<блок объявлений>]
Begin
<уничтожение собственных полей>
Inherited <имя деструктора>[{<параметры>)];
End;
16. Ссылочная модель Delphi.
17. Наследование.
Насле́дование — механизм объектно-ориентированного программирования (наряду с инкапсуляцией, полиморфизмом и абстракцией), позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса заимствуются новым классом.
Другими словами, класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса.
Дата добавления: 2015-11-16; просмотров: 141 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Поля, методы и свойства объектов. | | | Множественное наследование |