Файл: 4. Разработка простейшего объекта-контейнера.pdf

Добавлен: 20.10.2018

Просмотров: 994

Скачиваний: 8

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

 

 

 

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

 

  

 


background image

 

 

Особенность динамических массивов – это возможность изменять размер во 

время выполнения программы.  

Переход  на  новую  версию  контейнера  требует  небольших  изменений  в 

структуре классов и реализации методов: 

  изменяется объявление массива 

  вводится  новое  закрытое  свойство  –  текущий  размер  динамического 

массива и Get-метод доступа к нему 

  старый  конструктор  без  параметров:  изменяется  его  реализация  с 

целью  создания  массива  с  установленным  по  умолчанию  начальным 

размером  

  вводится  второй  конструктор  с  одним  входным  параметром, 

определяющим начальный размер массива 

  изменяется реализация метода добавления: при отсутствии свободного 

места в текущем массиве происходит его динамическое расширение

в  этом  случае  отказ  в  добавлении  происходит  только  при  отсутствии 

необходимой свободной динамической памяти 

  немного  изменяется  реализация  циклов  при  обработке  массивов, 

поскольку динамические массивы адресуются с нуля 

 

При  работе  с  динамическими  массивами  надо  учитывать  следующие  

особенности  их  использования.  Во-первых,  переход  к  новому  массиву 

другого размера – это выделение новой области памяти и занесение в нее 

данных  из  старого  массива.  Выполнение  этих  операций  требует  некоторого 

времени.  С  одной  стороны,  наиболее  эффективное  использование  памяти 

достигается  при  изменении  размера  на  один  элемент,  но  с  другой  стороны 

многократное  повторение  таких  операций  может  существенно  замедлить 

выполнение программы. Поэтому приходится идти на «вечный» компромисс 

память-время  и  ради  скорости  выполнения  немного  пожертвовать  памятью. 

На  практике  хорошо  показала  себя  следующая  рекомендация:  увеличить 

размер массива на 50-100 % от текущего значения. 


background image

 

 

Во-вторых,  в  отличие  от  классических  массивов,  переменная, 

определяющая  имя  массива,  является  указателем  на  область  памяти  с 

элементами этого массива. Для создания нового массива в 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 


background image

 

 

      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;

 

 

 

      // дин. массив ссылок на студентов 


background image

 

 

   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. Удалить студента: