- •Вопросы к итоговому государственному междисциплинарному экзамену по дисциплине «Объектно-ориентированное программирование»
- •Объектно-ориентированное программирование как методология разработки программ. Структура объектно-ориентированной программы. Привести пример описания объектного типа.
- •Соотношение основных понятий ооп. Привести примеры программного обращения или описания основных понятий ооп.
- •Принципы объектно-ориентированного программирования. Понятие инкапсуляции, наследования и полиморфизма. Привести примеры программного описания.
- •2 Основные характеристические свойства понятий
- •Простое и множественное наследование. Правила наследования. Привести пример простого наследования.
- •Скрытие данных в объектном типе. Назначение директив private и public. Привести пример управления доступом к элементам класса.
- •Понятие виртуального метода. Назначение и отличие виртуальных и динамических методов. Правила вызова виртуальных методов. Привести пример объявления виртуального метода.
- •Выделение памяти под экземпляр объекта. Привести пример объявления и реализации конструктора и деструктора.
- •Исключительные ситуации в терминологии ооп. Глобальная и локальная обработка исключений. Привести пример использования операторов контроля исключительных ситуаций при локальной обработке.
- •Понятие проекта Delphi. Состав проекта Delphi. Основные файлы проекта, их характеристика. Привести примеры программного кода основных файлов проекта.
Понятие виртуального метода. Назначение и отличие виртуальных и динамических методов. Правила вызова виртуальных методов. Привести пример объявления виртуального метода.
Методы могут быть виртуальными и динамическими. Они различаются способом решения классической проблемы «время — ресурс, ресурс — время» (в данном случае ресурс — это объем оперативной памяти).
Разница между ними заключается в структуре соответствующих таблиц методов VMT — Virtual Metod Table (таблица виртуальных методов) и DMT — Dynamic Metod Table (таблица динамических методов). Диспетчеризация виртуальных методов происходит быстрее, чем динамических, но с другой стороны, таблица виртуальных методов (VMT) занимает больше места в памяти, чем таблица динамических (DMT). Выбор остается за программистом.
Для определения типа метода (виртуальный или динамический) используются две директивы — virtual и dynamic соответственно. Для указания типа метода после его объявления через точку с запятой указывается одна из этих директив. Вот простой пример:
TMyClass = class(TCustomControl)
...
procedure SetStr(str: String); dynamic;
function GetStr: String; virtual;
...
end;
Виртуальные методы
Полиморфизм является необходимым средством при обеспечении расширяемости типов в приложениях. Он позволяет не переделывать структуру программы, если возникает необходимость, скажем, определения нового типа данных, например нового типа геометрической фигуры. Использование полиморфизма необходимо, если процедура построения фигур работает с фиксированным набором объектов, описанных в модуле, а пользователь, работающий с модулем, хочет определить новый тип фигуры. Для этого применяются виртуальные методы.
Метод становится виртуальным, если за его объявлением в типе объекта стоит зарезервированное слово VIRTUAL. Необходимо помнить, что если метод объявлен в родительском типе как VIRTUAL, то все методы с аналогичными именами в дочерних типах также должны объявляться виртуальными, во избежание ошибки компилятора.
Procedure <имя метода>(<список параметров>); virtual;
Function <имя метода> (<список параметров>):<тип функции>; virtual;
Конструктор является специальным типом процедуры, которая выполняет некоторую установочную работу для механизма виртуальных методов. Более того, конструктор должен вызываться перед вызовом любого виртуального метода.
Вызов виртуального метода без предварительного вызова конструктора может привести к блокированию системы, а у компилятора нет способа проверить порядок вызова методов.
Правила вызова виртуальных методов:
каждый тип объекта, имеющий виртуальные методы, обязан иметь конструктор;
каждый экземпляр объекта должен инициализироваться отдельным вызовом конструктора. Недостаточно инициализировать один экземпляр объекта и затем присваивать этот экземпляр другим. Другие экземпляры, даже если они содержат правильные данные, не будут инициализированы оператором присваивания и заблокируют систему при любых вызовах их виртуальных методов. Например:
VAR
One, Two: TPerson;
BEGIN
One.Init ('Петр Петров','25-06-1995', 400000);
Two: = One; (Неправильный вызов!)
END;
каждый тип объекта, содержащий виртуальные методы, имеет таблицу виртуальных методов (ТВМ), хранящуюся в сегменте данных. ТВМ содержит размер типа объекта и для каждого виртуального метода указатель кода, исполняющий данный метод. Конструктор устанавливает связь между вызывающим его экземпляром объекта и ТВМ этого объекта.
Необходимо учесть, что имеется только одна ТВМ для каждого типа объекта. Отдельные экземпляры объекта (т.е. переменные данного типа) содержат только адрес ТВМ, но не саму ТВМ. Конструктор устанавливает значение этого адреса. Поэтому вызов виртуального метода до вызова конструктора приведет к ошибке, т.к. к этому моменту поле адреса ТВМ еще не инициализировано и содержит неопределенный адрес.
При отладке программы для контроля правильности вызовов виртуальных методов можно использовать директиву компилятора $R. Если директива $R находится во включенном состоянии {$R+}, то все вызовы виртуальных методов будут проверяться на состояние инициализации объекта, выполняющего вызов метода. Если выполняющий вызов объект еще не был инициализирован конструктором, то произойдет ошибка выполнения. По умолчанию установлено значение {$R-}.
Однако отрицательной стороной использования данной директивы является замедление работы программы. Это происходит из-за того, что при каждом вызове виртуального метода дополнительно выполняется процедура проверки правильности инициализации. Поэтому, если скорость работы программы является критическим параметром, то рекомендуется использовать проверку виртуальных методов только на этапе отладки. Когда программа отлажена и гарантировано отсутствие вызовов виртуальных методов до вызова конструктора, директиву $R можно перевести в пассивное состояние {$R-}, что ускорит выполнение программы.
Если объявляется виртуальные метод в каком-либо родительском типе, то это накладывает следующие ограничения на его дочерние типы:
все методы дочерних типов одноименные с виртуальными родительскими, так же обязаны быть виртуальными;
после того как метод стал виртуальным, его заголовок не может изменяться в объектах более низкого уровня.
Заголовки всех реализаций одного и того же виртуального метода должны быть идентичными, включая число параметров и их типы.
Вызов виртуального метода осуществляется следующим образом:
Через объектную переменную выполняется обращение к занятому объектом блоку памяти;
Далее из этого блока извлекается адрес таблицы виртуальных методов (он записан в четырех первых байтах);
На основании порядкового номера виртуального метода извлекается адрес соответствующей подпрограммы;
Вызывается код, находящийся по этому адресу.
Пример описания типа, в котором объявлен виртуальный метод:
type
TPerson=class
fname:string;{ имя }
constructor Create (name:string) ;
function info: string; virtual;
end;
TStud=class(TPerson)
fgr:integer; { номер группы}
constructor Create(name:string;gr:integer);
function info:string; override;
end;
В каждом из этих классов определен метод info. В базовом классе при помощи директивы virtual метод info объявлен виртуальным. Объявление метода виртуальным дает возможность дочернему классу произвести замену виртуального метода своим собственным. В каждом дочернем классе определен свой метод info, который замещает соответствующий метод родительского класса (метод порожденного класса, замещающий виртуальный метод родительского класса, помечается директивой override).
Охарактеризовать понятия указателя и динамической переменной. Выделение и освобождение памяти для динамической переменной. Привести пример выделения и освобождения памяти для динамической переменной.
Память для хранения данных может выделяться как статически, так и динамически. В первом случае выделение памяти выполняет компилятор, встретивший при компиляции объявление объекта. В соответствии с типом встретившегося объекта вычисляется объем памяти, требуемый для его размещения. Класс памяти задает место, где эти объекты (данные) будут располагаться. Это может быть сегмент данных либо стек.
Часто возникают ситуации, когда заранее не известно, сколько объектов – чисел, строк текста и прочих данных будет хранить программа. В этом случае используется динамическое выделение памяти, когда память занимается и освобождается в процессе исполнения программы. При использовании динамической памяти (ДП) отпадает необходимость заранее распределять память для хранения данных, используемых программой. Управление динамической памятью – это способность определять размер объекта и выделять для его хранения соответствующую область памяти в процессе исполнения программы.
Динамической переменной называется переменная, память для которой выделяется во время работы программы.
Выделение памяти для динамической переменной осуществляется вызовом процедуры new. У процедуры new один параметр — указатель на переменную того типа, память для которой надо выделить. Например, если р является указателем на тип real, то в результате выполнения процедуры new(p); будет выделена память для переменной типа real (создана переменная типа real), и переменная-указатель р будет содержать адрес памяти, выделенной для этой переменной.
У динамической переменной нет имени, поэтому обратиться к ней можно только при помощи указателя.
Процедура, использующая динамические переменные, перед завершением своей работы должна освободить занимаемую этими переменными память или, т.е. уничтожить динамические переменные. Для освобождения памяти, занимаемой динамической переменной, используется процедура Dispose, которая имеет один параметр — указатель на динамическую переменную.
procedure TForm1.Button1Click(Sender: TObject);
var
p1,p2,p3: Integer; // указатели на переменные типа integer
begin
// создание динамических переменные типа integer
// (выделение памяти для динамических переменных)
New(p1);
New(p2);
New(p3);
р1^ := 5;
р2^ := 3;
р3^ := р1^ + р2^;
ShowMessage('Сумма чисел равна ' + IntToStr(р3^));
// уничтожение динамических переменных
// (освободим память, занимаемую динамическими переменными)
Dispose(p1);
Dispose(р2);
Dispose(р3);
end;
