- •3. Объектно-ориентированное программирование (ооп)
- •3.1. Краеугольные камни ооп
- •3.1.1. Что такое объект?
- •3.1.2. Концептуальный пример объекта
- •3.1.3. Природа объекта
- •3.1.4. Понятие класса объектов
- •3.1.5. Три кита ооп
- •3.1.6. Объекты и компоненты
- •3.2. Классы
- •3.2.1. Понятие класса
- •3.2.2. Классы в программных модулях
- •3.3. Объекты
- •3.4. Методы
- •3.4.1. Понятие метода
- •3.4.2. Конструкторы и деструкторы
- •3.5. Свойства
- •3.5.1. Понятие свойства
- •3.5.2. Методы получения и установки значений свойств
- •3.5.3. Свойства-массивы
- •3.5.4. Свойство-массив как основное свойство объекта
- •3.5.5. Методы, обслуживающие несколько свойств
- •3.6. Наследование
- •3.6.1. Понятие наследования
- •3.6.2. Прародитель всех классов
- •3.6.3. Перекрытие атрибутов в наследниках
- •3.6.4. Совместимость объектов различных классов
- •3.6.5. Контроль и преобразование типов
- •3.7. Статические методы
- •3.7.1. Понятие статического метода
- •3.8. Виртуальные методы
- •3.8.1. Понятие виртуального метода
- •3.8.2. Механизм вызова виртуальных методов
- •3.8.3. Абстрактные виртуальные методы
- •3.8.4. Динамические методы
- •3.8.5. Методы обработки сообщений
- •3.9. Указатели на методы объектов
- •3.12. Метаклассы
- •3.12.1. Ссылки на классы
- •3.12.2. Методы классов
- •3.12.3. Виртуальные конструкторы
- •3.13. Классы общего назначения
- •3.13.1. Классы для представления списка строк
- •Свойства:
- •Методы:
- •События:
- •3.13.2. Классы для представления потока данных
- •Общие свойства:
- •Общие методы:
- •3.14. Итоги
- •4. Исключительные ситуации и надежное программирование
- •4.1. Ошибки и исключительные ситуации
- •4.2. Классы исключительных ситуаций
- •4.3. Обработка исключительных ситуаций
- •4.3.1. Создание исключительной ситуации
- •4.3.2. Распознавание класса исключительной ситуации
- •4.3.3. Пример обработки исключительной ситуации
- •4.3.4. Возобновление исключительной ситуации
- •4.3.5. Доступ к объекту, описывающему исключительную ситуацию
- •4.4. Защита выделенных ресурсов от пропадания
- •4.4.1. Утечка ресурсов и защита от нее
- •4.5. Итоги
3.7. Статические методы
3.7.1. Понятие статического метода
По умолчанию, методы являются статическими. Пример описания:
Type TFigure = class procedure Draw; end; TRectangle = class(TFigure) procedure Draw; end; |
При обращении к статическому методу компилятору (то есть уже на этапе компиляции) известен класс, которому данный метод принадлежит. Следовательно, при помощи статических методов невозможно реализовать принцип полиморфизма. Пусть, например, имеется некоторая процедура, которая принимает в качестве параметра и базовый класс и классы-потомки. В качестве примера рассмотрим SetVisible. Класс объекта, к которому применяется эта процедура, становится известен этапе выполнения. И хотелось, чтобы и метод Draw был не базового класса, в котором описана процедура SetVisible, а каждый раз своего класса. Иначе рисовка фигурки не будет корректной. В этом случае метод Draw должен быть перекрыт в потомках.
3.8. Виртуальные методы
3.8.1. Понятие виртуального метода
Виртуальные методы, в отличие от статических могут быть перекрыты в классах-потомках.
1. Объявление виртуального метода в базовом классе выполняется с помощью ключевого слова virtual, а его перекрытие в производных классах — с помощью ключевого слова override.
2. Перекрытый метод должен иметь точно такой же формат (список параметров, а для функций еще и тип возвращаемого значения), что и перекрываемый:
Type TFigure = class procedure Draw; virtual; end; TRectangle = class(TFigure) procedure Draw; override; end; TEllipse = class(TFigure) procedure Draw; override; end; |
Суть виртуальных методов в том, что они вызываются по фактическому типу экземпляра, а не по формальному типу, записанному в программе.
var Figure: TFigure; rectangle: Trectangle; Ellipse: Tellipse; begin Ellipse.visible:=true; //Draw, Hide от TEllipse Rectangle.visible:=false; //Draw, Hide от TRectangle end; |
Работа виртуальных методов основана на механизме позднего связывания (late binding). В отличие от раннего связывания (early binding), характерного для статических методов, позднее связывание основано на вычислении адреса вызываемого метода при выполнении программы. Адрес метода вычисляется по хранящемуся в каждом объекте описателю класса.
3.8.2. Механизм вызова виртуальных методов
Работа виртуальных методов основана на косвенном вызове подпрограмм. При косвенном вызове команда вызова подпрограммы оперирует не адресом подпрограммы, а адресом места в памяти, где хранится адрес подпрограммы. Вы уже сталкивались с косвенным вызовом при использовании процедурных переменных. Процедурная переменная и была тем местом в памяти, где хранился адрес вызываемой подпрограммы. Для каждого виртуального метода тоже создается процедурная переменная, но ее наличие и использование скрыто от программиста.
Все процедурные переменные с адресами виртуальных методов пронумерованы и хранятся в таблице, называемой таблицей виртуальных методов (VMT — от англ. Virtual Method Table). Такая таблица создается одна для каждого класса объектов, и все объекты этого класса хранят на нее ссылку.
Структуру объекта в оперативной памяти поясняет рисунок 3.3:
Рисунок 3.3. Структура объекта TTextReader в оперативной памяти
Вызов виртуального метода осуществляется следующим образом:
Через объектную переменную выполняется обращение к занятому объектом блоку памяти;
Далее из этого блока извлекается адрес таблицы виртуальных методов (он записан в четырех первых байтах);
На основании порядкового номера виртуального метода извлекается адрес соответствующей подпрограммы;
Вызывается код, находящийся по этому адресу.