ВУЗ: Университет управления «ТИСБИ»
Категория: Учебное пособие
Дисциплина: Объектно-ориентированное программирование
Добавлен: 20.10.2018
Просмотров: 1154
Скачиваний: 8
if ( MyCont.Delete(2) = nil ) then «удаление невозможно»
else «удалили окружность 2»
6. Найти окружность по радиусу (например – 50):
MyCirc := MyCont.Search(50, N);
if (MyCirc = nil) then «не нашли» else «нашли под номером N»;
7. Изменить радиус окружности с заданным номером:
MyCirc := MyCont.GetCirc(Nomer);
if (MyCirc <> nil) then MyCirc.SetR(100);
При выполнении этой программы будут выделены следующие области
памяти:
для объектной переменной контейнерного типа
для самого объекта-контейнера
для включенных в контейнер объектов-окружностей
Схематично взаимосвязи между этими областями можно представить так:
Одно из важнейших достоинств объектной реализации состоит в том,
что разработчик классов может вносить изменения в свои классы
«незаметно» от пользователей, т.е. без необходимости переписывания
прикладных программ. В частности, простейший контейнер-массив можно
улучшить, заменив обычный массив его динамической версией.
ОП MyCont
адрес контейнера
объект-контейнер
счетчик адрес
окр. 1
адрес
окр. 2
. . . .
адрес
окр. 100
100
200
50
объект
окр. 1
200
100
150
объект
окр. 2
300
400
100
объект
окр. 100
Особенность динамических массивов – это возможность изменять размер во
время выполнения программы.
Переход на новую версию контейнера требует небольших изменений в
структуре классов и реализации методов:
изменяется объявление массива
вводится новое закрытое свойство – текущий размер динамического
массива и Get-метод доступа к нему
старый конструктор без параметров: изменяется его реализация с
целью создания массива с установленным по умолчанию начальным
размером
вводится второй конструктор с одним входным параметром,
определяющим начальный размер массива
изменяется реализация метода добавления: при отсутствии свободного
места в текущем массиве происходит его динамическое расширение;
в этом случае отказ в добавлении происходит только при отсутствии
необходимой свободной динамической памяти
немного изменяется реализация циклов при обработке массивов,
поскольку динамические массивы адресуются с нуля
При работе с динамическими массивами надо учитывать следующие
особенности их использования. Во-первых, переход к новому массиву
другого размера – это выделение новой области памяти и занесение в нее
данных из старого массива. Выполнение этих операций требует некоторого
времени. С одной стороны, наиболее эффективное использование памяти
достигается при изменении размера на один элемент, но с другой стороны
многократное повторение таких операций может существенно замедлить
выполнение программы. Поэтому приходится идти на «вечный» компромисс
память-время и ради скорости выполнения немного пожертвовать памятью.
На практике хорошо показала себя следующая рекомендация: увеличить
размер массива на 50-100 % от текущего значения.
Во-вторых, в отличие от классических массивов, переменная,
определяющая имя массива, является указателем на область памяти с
элементами этого массива. Для создания нового массива в Delphi/Free Pascal
используется стандартный вызов
SetLength (имя_массива, размер_массива );
Формальное объявление класса:
TDynArrayCircleContainer = class
private
Circs : array of TCircle; // динамический (!) массив указателей
count : integer; // не изменяется
size : integer; // новое свойство – текущий размер массива
public
constructor Create; overload; // старая форма – новое содержание
constructor Create (aSize: integer); overload; // новый конструктор
function GetCount : integer; // не изменяется
function GetSize : integer; // новый метод доступа
function GetCirc (nom : integer) : TCircle; // не изменяем
function Add (aCirc : TCircle) : boolean; // измененный метод
function Delete (ai : integer) : TCircle; // можно не изменять
function Search (aRad : integer; var Nom : integer) : TCircle; // немного
procedure ShowAll;
// изменяем
procedure MoveAll (dx, dy : integer);
// циклы
end;
Программная реализация нового конструктора:
constructor TDynArrayCircleContainer.Create (aSize : integer);
var i : integer;
begin
SetLength (Circs, aSize); // динамическое создание массива размера aSize
size := aSize;
// запомнили начальный размер массива
for i := 0 to (size-1) do Circs [ i ] := nil;
// заполнили нулями
count := 0;
end;
Измененный метод добавления:
function TDynArrayCircleContainer.Add (aCirc : TCircle) : boolean;
begin
result := true;
if ( count = size ) then
// места нет, надо расширить массив
begin
size := size * 2;
// увеличиваем размер в два раза
SetLength (Circs, size);
// создаем новый массив большего размера
// если памяти для нового массива нет, установить result := false;
end;
count := count + 1;
// лучше так: inc (count);
Circs [ count ] := aCirc;
end;
Использовать новую версию контейнера можно практически без каких-
либо изменений в прикладной программе, поскольку открытый интерфейс
класса почти не изменился.
Контейнер на основе динамического массива для объектов-студентов:
TDynArrayStudContainer = class
private
Name : string;
// информационное имя контейнера
Studs : array of TStudent;
// дин. массив ссылок на студентов
count : integer;
// число студентов
size : integer; // текущий размер дин. массива
public
constructor Create (aSize: integer); // создание контейнера заданн. размера
function GetCount : integer;
// запрос текущего числа студентов
function GetName : string;
// запрос имени
procedure SetName (newName : string); // изменение имени
procedure Add (newStud : TStudent); // добавление студента
function Delete (aFam: string) : boolean; // удаление студента по фамилии
function GetStud (nom : integer) : TStudent; // получение ссылки на студ-та
function Search (aFam : string) : integer;
// поиск студента по фамилии
procedure SortByFam;
// сортировка по фамилии
procedure SortBySredBall;
// сортировка по среднему баллу
end;
Фрагменты тестовой (пользовательской) программы:
1. Объявить объектную переменную контейнерного типа:
var Gruppa : TDynArrayStudContainer;
2. Создать пустой контейнер заданного размера с помощью конструктора:
Gruppa := TDynArrayStudContainer.Create (20);
3. Добавить в контейнер объекты-студенты:
Stud := TStudent.Create('Иванов');
Gruppa.Add (Stud);
4. Циклически обработать контейнер:
Gruppa.SortBySredBall;
5. Удалить студента: