- •Объектно-ориентированное программирование
- •Часть 1 классы и объекты
- •Введение
- •1. Классы и объекты
- •Var aLine: tLine;
- •Var aColorLine: tColorLine;
- •2. Методы
- •2.1. Методы-функции и методы-процедуры
- •2.2. Конструкторы и деструкторы
- •Inherited Create;
- •Var TmpFrm: tForm;
- •Var Mem: tMemo;
- •2.3. Классовые процедуры и функции
- •Var s: String;
- •2.4. Скрытый Self
- •3. Видимость компонентов класса
- •4. Наследование
- •4.1. Основные понятия
- •4.2. Наследование полей
- •4.3. Поведение методов при наследовании
- •Var SomeObject: t1;
- •Virtual;
- •Virtual; Abstract;
- •4.4. Иерархия классов
- •4.5. Rtti
- •4.6. Проверка типа
- •4.7. Приведение типа
- •4.8. Указатели на класс
- •Var ObjRef: tObjRef;
- •Implementation
- •X, y, w, h: Integer): tControl;
- •5. Полиморфизм
- •6. Свойства (properties)
- •6.1. Объявление свойств
- •6.2. Объявления свойств-массивов
- •Var I: Byte;
- •6.3. Раздел Read
- •6.4. Раздел Write
- •Inherited Create;
- •Inherited Destroy;
- •6.5. Команды Default, NoDefault и Stored
- •6.6. Команда Index
- •Var aYear, aMonth, aDay: Word;
- •Var aYear, aMonth, aDay: Word;
- •6.7. Команды DispId и Implements
- •6.8. Переопределение свойств при наследовании
- •7. События (events)
- •7.1. Объявление событий
- •IfAssigned(fOnMouseMove) Then fOnMouseMove(Self, Shift, X, y);
- •Vk_return: NumMemo.DoNumStr(l);
- •Vk_return: PostMessage(NumMemo.Handle, wm_user1,1, 0);
- •7.2. Обработчики событий
- •7.3. Делегирование событий
- •Var Objl: tIstClass;
- •7.4. Переопределение стандартных событий
- •Var NewBtn: tNewButton;
Var ObjRef: tObjRef;
S: String;
Begin
ObjRefs^TMyClass; // Ссылка на класс, а не на экземпляр
S:=ObjRef.ClassName; // Строка S содержит строку "IMyClass'
. . .
S:=Sender.ClassName; // Строка S содержит имя класса
• Используя классовые ссылки, можно достичь своего рода полиморфизма при создании экземпляров объектов в процессе работы программы.
Type
TMyControl=Class OfTControl;
. . .
Implementation
Function MyCreate(MyClass: TMyControl; Const MyName: String;
X, y, w, h: Integer): tControl;
Begin
// Создаем новый объект, класс которого MyClass
Result:=MyClass.Create(Forml);
With Result Do Begin
Parent:=Fonnl; // Parent: =Forml.Panell; - на другом контейнере
Name:=MyName;
SetBounds(X. Y, W, H);
Visible:=True;
End;
End;
Begin
// Создание поля ввода в нужном месте производится следующим образом
MyCreate(TEdit, 'Editi', 10,10,100,20);
• Для динамического удаления компонентов можно воспользоваться свойствами ComponentCount и Components [Index] и оператором Is или использовать функцию FindComponent.
• For I:=0 To ComponentCount-l Do
lfComponents[I| Is TEdit Then Components|I].Free;
• FindComponent('Editl').Free;
• FindComponent(TControl(Sender).Name).Free;
Фактически Delphi использует виртуальный конструктор, создавая компоненты на форме после вашего щелчка по компоненту на палитре компонентов и форме.
5. Полиморфизм
Полиморфизм (или много форм) - третья и самая мощная грань ООП. Полиморфизм может быть описан как поведенческая абстракция, - возможность вызывать действие или поведение по имени какого-либо конкретного экземпляра класса, не зная в точности, какая именно реализация метода при этом будет вызвана, и даже не зная в точности, к какому типу принадлежит данный объект. Тип экземпляра класса и реализация метода, который будет вызван в процессе выполнения программы, не могут быть полностью определены на фазе трансляции. Более того, процесс будет выполняться динамически - один и тот же код может работать с экземплярами разных классов.
Ключевой момент в виртуальных методах - указатели на код, хранящийся в VMT, а ключевой момент в полиморфизме - использование данных экземпляра класса для получения указателя на нужную таблицу VMT во время выполнения программы. Действительно, у компилятора нет возможности определить класс объекта, фактически передаваемого для обработки в процессе выполнения программы. Поэтому нужен механизм, позволяющий определить это непосредственно во время выполнения, - это называется поздним связыванием (late binding). Этот механизм должен быть связан с передаваемым объектом. В качестве такого механизма и служат VMT и DMT.
Таким образом, полиморфизм - это механизм, позволяющий во время
работы программы установить родительский объект равным одному из дочерних.
Для реализации полиморфизма подходят две схемы взаимоотношения класса-предшественника и производного класса:
• есть класс-предшественник, в котором объявлен один или более виртуальных (динамических) методов. Имеется производный класс, в котором
произведено замещение одного или более виртуальных (динамических) методов класса-предшественника;
• есть класс-предшественник, в котором объявлен один или более абстрактных метода. Имеется один или более производных класса, в которых переопределены абстрактный метода класса-предшественника.
Экземпляр производного класса можно присвоить переменной класса-предшественника, но обратное невыполнимо, поскольку объект производного класса больше объекта класса-предшественника, поскольку включает новые поля и/или методы. Более того, если бы это было возможно, то экземпляр класса-предшественника мог бы обращаться к полям и методам, которых у него нет.
Таким образом, полиморфизм возможен тогда, когда имеется:
• класс предшественник, определяющий один или более виртуальных методов;
• один или более производных классов, которые могут замещать эти виртуальные методы;
• переменная представителя класса, объявленная, как переменная типа класса-предшественника, но реально содержащая представителя одного из производных классов.
Type
TBaseClass=CIass // Базовый класс
FDate: TDateTime;
Function GetDate: String; Virtual; Abstract;
End;
TDateCIass=Class(TBaseClass) // Первый производный класс
Function GetDate: String; Override;
End;
TTimeCIass=Class(TBaseClass) // Второй производный класс
Function GetDate: String; Override;
• В обработчиках событий OnClick всех указанных компонентов указать FormClick.
• После запуска формы можно щелкнуть по любому компоненту, и будет происходить его перемещение в другое место (или перерисовка -Repaint), которое для каждого из них будет происходить известным для него способом, иначе все компоненты были бы одинаковыми.
Если в этом примере заменить исполняемый код на:
(Sender As TControl).Hint:='Это ярлычок!';
и установить свойство ShowHint экранной формы в True, то после щелчка мышью по форме ярлычки будут далее появляться у всех компонентов. Это пример полиморфного присвоения. Щелчок по компоненту приводит к появлению подсказки у него.
Поскольку все используемые компоненты являются потомками от TControl, они обрабатываются одинаково, т.е. всем присваивается одинаковое значение.
Необходимость в использовании полиморфизма проявляется в ситуациях, когда, посылая разным объектам одно и то же сообщение, вы хотите, чтобы каждый из объектов реагировал на него особым способом. Каждый объект должен иметь уникальную реакцию на это сообщение, но желательно, чтобы эти функции имели одно и то же имя.
У каждого классового типа есть своя уникальная VMT (DMT). Блок данных экземпляра каждого типа содержит скрытый указатель на VMT своего класса (напомним, что VMT - это принадлежность класса, а не экземпляра или объекта). Когда транслятору нужно сгенерировать код для вызова виртуального метода, он сначала генерирует код для получения указателя на VMT из данных экземпляра, затем получает адрес кода нужного метода из соответствующего поля VMT и далее выполняется вызов по полученному адресу.
Полиморфизм использует абстракцию и помогает ей, используя обобщенные процессы для управления родственными специализированными реакциями. За счет малого количества кода контролируется обширный набор вариантов поведения.