Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


ООП

Поиск:
Объектно-ориентированное программирование для начинающих на Паскале.

"Объектно-ориентированное..." - это значит работа с объектами. Что в нашей жизни мы можем назвать объектами? А все что угодно. Стол, за которым сидим, машина в которой едим, воздух, которым дышим, ... - Это все РЕАЛЬНЫЕ объекты и мы их можем хорошо представить, вообразить как они будут себя вести, что будут делать. Кстати, чем отличается, СТОЛ и САМОЛЕТ как объекты? Ну первая, пришедшая в голову мысль, что сравнивать их как-то не очень хочется, совсем они разные... Вот тут-то мы и пришли к одному из характеристик объектов, а именно к свойствам. Как Вы пытались сравнивать стол и самолет? Наверное пытались найти в них, что-то общее или наоброт то чем они отличаются. Ну так вот на самом то деле два приведенных выше объекта имеют много общего :) Их можно "сравнивать" по материалу изготовления, в одном случае это будт дерево, а в другом - металл; по весу, ну скажите мне какой объект не имеет веса? ; можно сравнивать по цвету, габаритам, .....
Вот первое, что мы должны понять это то что объекты характеризуются СВОЙСТВАМИ. А вот значения этих свойств у объектов может быть разное (материал изготовления, например).
Давайте подумаем, чем есчо могут отличаться Самолет и Стол? Наверное манерой поведения, то есть их действиями и реакцией на определенные действия. Например Самолет будет иметь характеристику "Скорость", которая будет изменяться, а для Стола эта характеристика безсмысленна. Хорошо есть у нас свойство "скорость", а как ею распоряжаться? Самолет может покоиться на аэродроме, набирать скорость при взлете и тормозить при посадке. Что это такое: покой, набор скорости, торможение? К свойствам они наверное отновшения не имеют. Как например вы можете оценить свойство "набор скорости"? Можно конечно сравнивать с другими подобными объектами и говорить о понятиях быстрее, медленнее. Но к ООП это ни какого отношения иметь не будет. На самом деле с точки зрения ООП покой, набор скорости, торможение - это действия производимые объектом. Действия, в ООП их называют Методами, управляют Свойствами. Например Методы набор_скорости и торможение изменяют Свойство скорость, уменьшаю её или увеличивают. Кстати в классике ООП только методы могут изменять значения свойств, ну что бы не было безконтрольного их изменения из вне. Что например произойдет если скорость станет равной -34 км/ч? Да, методы призваны контролировать свойства, давая им осмысленные значения, и естествено правильный метод "торможение" никогда не допустит уменьшение скорости, когда оно достигнет нулевой отметки. :)

Итак для объекта характерны свойства и методы. В программировании то же можно найти вагон и маленькую тележку "виртуальных" объектов. Может быть вы уже слышали про среду Delphi, в которой создаются приложения под Windows, там все рассматривается как объекты, например Кнопки, надписи, флажки, окна и само приложение - это все объекты. Для тренировки: какие свойтва есть у кнопки? Ну наверное, надпись на ней, цвет этой надписи, возможность изображения на кнопки картинки,.. и т д и т п.
В среде DOS при программировании на обычном Паскале, то же можно найти кучу объектов. Например, среда Turbo Pascal (Borland Pascal), в которой есть меню, окна, диалоги, а это ведь то же объекты. Даже если у вас нет такого сложного графического интерфейса вы то же можете использовать ООП для решения своей задачи, например, задача решения квадратного уравнения. Ну ка скажите мне где здесь объекты?......А само уравнение - это и есть объект, Какие у него свойства? а наверное коэффициенты перед Х. А методы? наверное очень хороший метод я придумал: "РЕШЕНИЕ", в котором происходит непосредсвенное вычисление, наверное можно было сказать, что есть есчо и метод "Вычисление_дискриминанта", - это будет промежуточный метод :)

Мир Объектно-Ориентированного программирования велик! Начнем его познавать с точки зрения языка Паскаль (хочу заметить что нижеследующие синтаксис, и теоретические выкладки сделаны опираясь на собственном опыте и предназначено для использования в DOS компиляторах Паскаля, например Turbo Pascal или Borland Pascal. Теория собсно может быть полезна и Delphi программисту, хотя есть кое-какие моменты в этом отношении, о чем разговор есчо будет)

Любой объект в паскале это просто новый тип данных, объявляеммый в разделе описания типов Type с использованием специальной терминологии языка.
Синтаксис будет следующим:
Код

Type
  TMyObject = Object
  ...
  End;

имена типов - о вашему усмотрению, но рекомендуется все типы начинать с буквы T. Для описания объктов используется ключевое слово object, заканчивается описание ключевым словом End. Очень напоминает объявление записи (record). Вместо точек пишутся члены класса..... тьфу, ну вот... сказал класса... Дело в том что есть некоторая "путаница" в терминологии в принципе понятие "объект" и "класс" - оба из ООП и очень близки по значению."Класс" - это описание, так сказать теоретическая часть ООП; "объект" - это КОНКРЕТНЫЙ ЭКЗЕМПЛЯР класса в оперативной памяти. Например, выше мы говори о самолетах. Термин "Самолет" - это класс, ни чего нам не говорящий о действительном объекте. А вот если мы с Вами сядем в первый класс какого-нить там Боинга-747, то будем иметь дело уже с конкретным экземпляром класса - т е с "объектом". В паскале слова класс как такового нет, хотя на самом деле подразумевается. То что мы с вами объявляем в разделе Type - в классике это класс, хотя и используем ключевое слово object, Ну а так как это тип данных => можно объявить переменную:
Код

Var
  MyObject: TMyObject; 

Это уже будет конкретный экземпляр класса, т е объект. В дальнейшем, то что касается описательной части я буду называть это КЛАССОМ (ибо привык уже :) ), а что касается конкретных экземпляров - это будут ОБЪЕКТЫ.
Итак мы знаем, что у объектов есть свойства, например, цвет, скорость, текущее состояние - все это данные, которым можно давать какие-то значения, тип данных у свойств различный, одни могут быть числами, другие- строки, третьи могут сами представлять из себя объекты...Ну так вот свойства - это данные, объявляются примерно так как запись:
Код

Type
   TMyCar= Object        //класс - "машина"
       Speed:Real;    // скорость машины
       Color:TColor;    // цвет
       ListWheels:Array[1..4] Of TWheel; // набор колес (4 штуки) TWheel пусть был обявлен ранее, и представляет собой класс - "колесо" со своими свойствамии методами
       .... //и так далее
   End;

Cо свойствами (данными) работают методы - подпрограммки (вспомните методы "торможение", "набор_скорости"). Описываются в классе с применением спецификаторов procedure и function.В самом объявлении, т е в классе, т е в разделе Type, описываются только заголовки подпрограмм. Итак наша машина обретает методы:
Код

Type
   TMyCar= Object    //класс - "машина"
       Speed:Real;
       Color:TColor;
       ListWheels:Array[1..4] Of TWheel;
       .... //и так далее
       procedure BeginMove(A:Real;Time:Integer); // "набор_скорости", будет происходить в течении времени Time с ускорением A
       procedure EndMove(A:Real); // "торможение" с ускорением A - будет продолжаться пока скорость не станет равной 0 => параметр по времени не задаётся
       function IsStay:Boolean; // метод-функция - возвращает логическое значение, которое будет означать в каком состоянии находится машина (покоится или движется)
   End;

Реализация методов класса должна происходить отдельно, то есть нельзя сразув разделе Type писать операторы программы которые будут реализовывать нужный метод. Это надо делать после объявления. При этом снова указывается вид метода (подпрограмма или функция), затем делается ссылка на тип класса (к какому классу относится реализуемый метод) и наконец, через точку, имя реализуемого метода. По вкусу моно есчои параметры метода перечислить. Например, реализация методов "машины":
Код

   procedure TMyCar.BeginMove; // лень мне параметры перечислять снова, вот я и не пишу про время и ускорение, однако я должен помнить что они есть!
   begin
       if IsStay then // если машина стояля (метод-функция из нашего класса)
           speed:=A*Time // то скорость такая
       else // она двигалась, но тут её есчо решили придать ускорения :)
           Speed:=Speed+A*Time
   End;
   procedure TMyCar.EndMove(A:Real); //а тут я по всем правиламя и параметры указал :)
   Begin
       While Speed>0 Do // пока не остановились
           if Speed>=A then    // каждую секунду уменьшаем скорость
               Speed:=Speed-A // на величину ускорения
           Else // или
               Speed:=0        // до нуля, раз текущая скорость была меньше ускорения
   End;
   function TMyCar:IsStay:Boolean;
   Begin
       IsStay:=Spped=0; // стоит-это значит скорость равна нулю
   End;

Конечно реализации всех этих методов "выпендреж", в первом можно было сразу написать Speed:=Speed+A*Time, во втором Speed:=0 - но надо же мне было что-там там придумать, да и к тому же машина не сразу ведь тормозит, так что метод EndMove немного приближен к реальности :)

Теперь немного об обращениик членам объекта,а они - свойства и методы.
Да, прежде чем обращатьсяк какому-нить члену объекта, этот самый объект надо заиметь в памяти:
Код

Var
   Car:TMyCar;

Я уже упоминал как происходит реализация методов, точнее как озаглавливаются методы классов - через точку. То же происходит и при обращении к свойствами методам в объекте (т е в экземпляре класса):
Код

Car.Color:=clYellow; // красим нашу машинув желтый цвет :)
Car.BeginMove(5.5, 15); // начинаем двигаться
WriteLn('Текущая скорость машины:', Car.Speed);
Car.EndMove(3.6); // останавливаемся
if Car.IsStay Then
   writeLn('Машина остановилась')
else
   writeLn('Машина почему-то продолжает двигаться!!!К чему бы это?');

Как видите все просто: имя переменной, ответственной за объект, точка (большая и жирная!),и свойсво или метод.
Как и к записям, к объектам можно применять оператор With, например:
Код

with Car Do Begin
   Color:=clYellow; // красим нашу машинув желтый цвет :)
   BeginMove(5.5, 15); // начинаем двигаться
   WriteLn('Текущая скорость машины:', Speed);
   EndMove(3.6); // останавливаемся
   if IsStay Then
       writeLn('Машина остановилась')
   else
       writeLn('Машина почему-то продолжает двигаться!!!К чему бы это?')
end;

Если все оставить как есть то хорошего получится не очень-то много. Например, мы с вами "красили" машину, простым присваиванием значения свойству, ответственному за цвет машины. Аналогично мы можем изменить и другие свойсва, просто обратившись к ним, например:
Код

Car.BeginMove(5.5, 15); // начинаем двигаться
Car.Speed:=-34; // обращение к свойству напрямую
WriteLn('Текущая скорость машины:', Car.Speed, "км/ч");

ну что это, что это, за народное творчество понимаешь...

Текущая скорость машины -34 км/ч

Как скорость машины может быть отрицательна???! Ладно мы с вами не дуракии вот так с нашей бедной машиной явно поступать не собираемся, но вот сдадим мы её в прокат, не знакомому человеку....А он то, зараза такой, возьмет да и скажет: "Хочу скорость 100000000 км/ч", т е
Car.Speed:=10000000;- такого тоже быть не может, что от машины тогда останется...

Для того что бы такого не происходило свойства обычно "прячут" от глаз,и пользоваться разрешается только методами. В этом случае, если мы хотим изменять скорость как нам хочется добавим новый метод:
Код

Type
   TMyCar= Object    //класс- "машина"
       ....
       procedure ChangeSpeed(NewSpeed:Real); // изменение скорости
       ....
   End;
procedure TMyCar.ChangeSpeed; // опять лень одалевает :)
Begin
   if NewSpeed<0 then
       writeLn('Такого просто быть не может!') //и не изменяем скорость
   else
       if NewSpeed>180 then
           writeLn('ГИБДД оштрафует...') //и тоже скорость не изменяется
       else
           Speed:=NewSpeed //а иначе скорость нормальная-изменяем
End;

И теперь вместо Car.Speed:=-34и Car.Speed:=10000000; надо будет использовать метод ChangeSpeed:
Код

Car.ChangeSpeed(-34);        // скорость
Car.ChangeSpeed(10000000);    // не измениться
Car.ChangeSpeed(80);    //а тут все нормально

Теперь видите как происходит контроль за значением свойств объекта?

Да я есчо не расказал как же все запретить напрямую изменять свойства. Для этого их нужно по особому описать, сказать что они не доступны для "массового использования" т е личные они. Делается это с помощью ключевого слова private. А то что изменять можно (например, нам "по барабану" какого цвета машина) то сказать, что оно "публичное" - доступное широкому обозрению - ключевое слово public, закрытыми (не доступными) можно делать не только свойства класса но и его методы.Вот например как лучше объявить наш класс при описании:
Код

Type
   TMyCar= Object    //класс - "машина"
       private        // все что ниже объявлено - то личное и недоступно для непосредственного изменения из вне
           ListWheels:Array[1..4] Of TWheel;
           Speed:Real;
       public //а теперь то что ниже этого - видно "широкому кругу лиц"
           Color:TColor;
           procedure ChangeSpeed(NewSpeed:Real); // изменение скорости
           procedure BeginMove(A:Real;Time:Integer); // "набор_скорости"
           procedure EndMove(A:Real); // "торможение"
           function IsStay:Boolean; // метод-функция (покоится или движется машина)
   End;

Дальнейшее изучение ООП мы продолжим, решая практическую задачу. Нам надо рассмотреть такие "страшные" термины как "наследование", "полиморфизм" и "инкапсуляция". Кстати частично инкапсуляцию мы уже посмотрели и применили - это использование слов public и private для определения видимости членов класса вне его. Мы как бы заключили наш объектв "капсулу". Но капсулы бывают разные: одни полностью прозрачные, другие непрозрачные вовсе. Вот те которые прозрачны - их консистенция (то из чего они состоят) видна (в ООП соответсвует public).А непрозрачные капсулы предстовляют собой "черный ящик" - их содержимое нам неизвестно(private).
А практическая задача будет следующая: нам надо написать на паскале (пусть компилятором будет Borland Pascal), некую аналогию программы Paint, в которой можно рисовать графические примитивы, такие как точки, окружности, линии, прямоугольники, в том числе и закрашенные. На этой задаче я попробую объяснить что такое наследование и полиморфизм.

Начнем.

Но прежде немного теории про наследование. Наследование - это один из принципов ООП, позволяющий применять уже существующие классы, расширяя их функциональность. Опять отвлекусь на автомобили. Сколько их у нас может быть? Легковые автомобили (Ока, Москвич, Волга и т д), грузовые автомобили (КАМАЗ, ГАЗ, МАЗ и т д). И у каждого из них есть общие свойства: цвет, число_колес, объем_бензобака, и т п.; а кроме этого у них есть и общие методы: набор_скорости, торможение... Правда реализация этих методов для каждого класса будет своя. Но тем не мение как вам перспектива описывать все это для каждого класса, для КАМАЗА описать свойства и методы, для Волги то же самое, аналогично и для других автомобилей? Правда, лень :) и ООП идет к нам на встречу! Оказывается можно описать некий базовый класс, пусть он так и называется "Просто_Автомобиль", в котором и будут все эти базовые свойства и методы, а затем "породить" от него потомка, например "Легковой_Автомобиль". В этом новом классе описывать заново свойства и методы, которые НЕ ОТЛИЧАЮТСЯ от базового НЕНУЖНО, они автоматически от него НАСЛЕДУЮТСЯ. Но все таки отличия между "Просто_Автомобилем" и "Легковым_Автомобилем" есть, например, при описании метода Набор_скорости "Просто_Автомобиля" мы не могли точно определить как расходуется горючее. Так ведь? Зато у "Легкового_Автомобиля" мы уже можем сделать некоторые предположения, например не больше 1л на 100км :). Также мы можем создать класс "Грузовой_Автомобиль", наследуя от базового класса все что в нем есть, определяя лишь специфические свойства и методы. Все! Скучная теория позади!
Теперь перейдем к нашем DosPaint`у. Всё что мы будем рисовать у нас будет объектами. Каждый из них нам придется описывать. Но смотрите у каждого из объектов будет некоторый набор общих свойств, например, цвет линий, которыми объект будет вычерчен; "начало" объекта (пара координат), для точки, это же будет и "концом", для окружности - это центр её, для линии - один из концов, и т д. Поэтому раз нам всем большой лень :) создадим базовый объект, в котором и будет все это общее:
Код

Type
   TPoint=Record  //введем вспомогательный тип "точка"
       X:Integer;        // кордината Х
       Y:Integer        // координата Y
   End;
   TBaseGraphObject=Object  // базовый объект
       private        // т к свойства лучше скрывать от любопытных глаз, то так и сделаем
           Color:Integer;  // цвет линий
           BeginPoint:TPoint;    // это и будет наше "начало"
           IsShow:Boolean;  // флаг, который будет говорить о том нарисован ли объект или есчо нет
       public        // а вот методы делаем открытыми
           Procedure Draw;  // рисование графического примитива
           Procedure ChangeColor(NewColor:Integer);  // смена цвета
           Procedure Hide;  // отмена рисования
           Procedure ChangeLocation(NewPoint:TPoint); // изменение местоположения объекта (изменение нашего "начала")
   End;

И снова остановимся. Для чего мы ввели флаг IsShow кто-нибудь догадывается?! Думайте, думайте, я помолчу...
Придумали? Правильно, он нам нужен для подпрограмм производящих изменения с объектом, например, изменение цвета (ChangeColor), что будет происходить при вызове этого метода? Ну вопервых будет меняться цвет (переменная Color). А если объект был отображен на экране то тут же его надо и перерисовать, а если мы его есчо не рисовали, то изменим Color молча и больше делать ничего не будем. Вот для того что бы делать есчо чего-нить или не делать кроме непосредственного изменения свойства и служит IsShow. А менять мы его будем в подпрограммых Draw и Hide, котоые выводят и прячут наше изображение соответственно. Ну, все прояснили, начнем реализовывать:
Код

Procedure TBaseGraphObject.Draw;   // надо нарисовать
Begin    // Так стоп! а что рисовать-то? у нас ведь это некая "абстракция" для окружности будем окружность рисовать
       // для линии - линию, а здесь объект не определен, поэтому рисовать ничего ненадо, только вот то что объект
       // будет нарисован, после выполнения этого метода надо отметить:
   IsShow:=True        // т е нарисовали... якобы...
End;
Procedure TBaseGraphObject.Hide;    //аналогично отрисовки, это только
begin                        //базовый объект, поэтому как скрывать мы не знаем, потом что
                           //незнаем как рисовали
                           // а вот результат действия отметить надо:
   IsShow:=False;
End;
Procedure TBaseGraphObject.ChangeColor(NewColor:Integer);  // смена цвета
   Var
       OldShow:Boolean;
begin
   if NewColor In [0..16] Then  // было введено корректное значение цвета => изменяем
       Begin
           OldShow:=IsShow;// надо, т к методы Hide и Draw, которые могут быть вызваны изменяют
                       // свойство IsShow и оно может быть неверно
           // сначала определяем был ли объект нарисован
           if OldShow Then    // если да то
               Hide;        // перед изменением надо объект "скрыть"
           Color:=NewColor;  // изменяем и...
           // перерисовываем объект
           if OldShow Then  // но только если он раньше был нарисован
               Draw
       End
   // а иначе ничего не далеем, т к цвет выходит за границы допустимого диапазона.
End;
// примерно аналогична я подпрограмма изменения местположения :
Procedure TBaseGraphObject.ChangeLocation;
   Var
       OldShow:Boolean;
begin
   OldShow:=IsShow;// надо, т к методы Hide и Draw, которые могут быть вызваны изменяют
               // свойство IsShow и оно может быть неверно
   // сначала определяем был ли объект нарисован
   if OldShow Then    // если да то
       Hide;        // перед изменением надо объект "скрыть"
   BeginPoint.X:=NewPoint.X;// изменеям
   BeginPoint.Y:=NewPoint.Y;// координаты
   // перерисовываем объект
   if OldShow Then  // но только если он раньше был нарисован
       Draw
End;

Уфф... Не расслабляться!!! это есчо не все, даже для базового объекта!
Давайте предположим, что кто-то (не мы конечно, мы то знаем как наши классы функционируют, и так делать не будем!), создаст в памяти объект (переменную объявит), и тут же воспользуется методом Draw, например, неустанавливая координат и цвета. Что получится? Конечно вы можете сказать что все вновь созданные переменные могут обнулиться, что Color=0; BeginPoint.X=0; BeginPoint.Y=0; IsShow=False... и метод Draw отобразит нам то что мы пытаемся нарисовать, относительно начала координат, черным цветом (Color=0 - черный). Но это ведь неверно, хотя бы цвет-то надо изменить на нормальный! Но наш пользователь этого не знает. Он сразу: раз, и Draw! Что делать? и тут ООП бежит к нам навстречу! Надо просто создать определенный метод, который будет инициализировать наш объект, давая свойствам какие-то первоначальные значения. Такой метод называется конструктором. Он конструирует создаваемый объект. И теперь, прежде чем объект мы будем эксплуатировать так, как нам вздумается он сначала сконструируется, а затем будет нам подвластен!
Те классы которые раньше использовали конструкторов не имели, и тем не менее они рабочие, однако для динамических объектов (о них мы поговорим ниже), наличие конструктора чуть ли не обязательное правило для правильного функционирования создваемого объекта. Конструктор, кроме инициализации свойств объекта, занимается важным делом для динамических объектов - он размещает объект в памяти и есчо кое-что делает :), об этом кое-чем, мы также есчо поговорим. Ну и забигая вперед, скажу , что конструкторов есть есчо один вид методов, которые в противоположность конструкторам, уничтожают объект, когда он уже не нужен, эти методы - деструкторы
Конструкторы и деструкторы отличаются от остальных методов, поэтому для них созданы специальные ключевые слова Constructor и Destructor соответственно, которые используются вместо procedure и function.
Именовать конструкторы и деструкторы можно по разному, но лучше, (почти обязательно!), когда конструкторы и деструкторы имеют одинаковые имена, для всех классов, так гораздо понятнее, что это метод - конструктор, а этот - деструктор. Чаще всего конструкторы имеют имя Init(что характерно для Turbo и Borland Pascal`ей или Create - для Delphi), деструкторы - Done(или для Delphi - Destroy)

Ну так вот давайте наш класс TBaseGraphObject оснастим конструктором и произведем в нем инициализацию свойств класса:
Код

Type
   TBaseGraphObject=Object  // базовый объект
       private        
           ...
       public        
           Constructor Init;  // конструктор
           ...
   End;
// реализация конструктора:
Constructor TBaseGraphObject.Init;
Begin
   Color:=White;  // пусть цвет линий по умолчанию будет белым
   IsShow:=False;  // объкт есчо не рисовался
   With BeginPoint Do Begin
       X:=0;
       Y:=0
   End
End;

Теперь пользователь (опять таки если он не вандал :) ) сначала сконструирует объект, а потом будет "мучить" методы объекта!

Что думаете с базовым классом покончено? :) Ничего подобного, осталось совсем чуть-чуть, зато потом будет все очень просто.
Прежде чем продолжить, отвлекемся еще на нескольк важных моментов при использовании ООП.
1) Размер объекта.
Когда мы используем много обычных переменных, например массив записей, каждая из записей, например, содержит три поля - одно числовое (4 байта), второе логическое(1 байт), третья - строка длиной до 255 символов (256 байт). Если в массиве около 200 элементов, то объем памяти, занимаемой такой структурой ~ 51КБ. Довольно много, однако, когда мы используем объекты, то кроме непосредственно данных, в памяти хранятся еще и указатели на методы объекта, таким образом объем объекта с теми же тремя полями (свойствами), у которого есть методы будет занимать больше места в памяти чем только запись с данными => массив объектов, еще более громаден. В DOS нельзя организовывать структуры больше 64К за раз. Хотя "по отдельности" можно организовать довольно большие структуры. Это достигается с применением указателей и использования динамической памяти.
Т к любой объект довольно большая структура данных, то использовать непосредственно статические объекты не рекомендуется, лучше создавить объекты по мере нуждаемости в них, и удалять их когда они больше не нужны.
2)Модульное построение программы
Группа объектов, точнее классов, которые объявляются программистом решают какую-то часть большой задачи. Даже если задача не сильно большая, может получится так, что часть объектов можно отнести к одной подзадаче, вторую часть - другой. Для реализации методов объектов может потребоваться много строк программного кода. А если еще учесть, что разные классы могут содержать одинаковые методы, в том числе если есть объекты порожденные от одного предка, то для нахождения нужной реализации одного или другого метода одного или нескольких объектов может быть весьмя проблематично. Поэтому часть родственных классов, например базовый класс и его потомков, луче поместить в одном модуле. При этом описание класса (раздел Type) выносится в интерфейсную часть модуля (Interface), а реализация методов - в часть реализации модуля (Implementation). Разбив большуя задачу на подзадачи, каждую из которых решать в отдельном модуле, гораздо проще и легче, чем "пихать" все в одну программу, достигающую несколько десятков тысяч строк. Тем более затем, в случае отладки или доработки найти нужную часть будет проще.

Ну программа у нас не глобальных масштабов, поэтому модули мы использовать не будем, а вот насчет указателей и динамической памяти - перестроим (пока не поздно) нашу программу. Для этого много не надо - всего лишь добавить есчо один тип данных - ссылка (указатель) на наш класс:
Код

Type
 PBaseGraphObject=^TBaseGraphObject; // тип-указатель
 TBaseGraphObject=Object  // базовый объект
     ...

как видите имя типа-указателя, отличается от имени основного типа лишь заменой буквы T на P, сокращение от имени Pointer - указатель, рекомендую и вам придерживаться того же стиля программирвоания.

вот посмотрите как использовать статические объекты:
Код

Var
 obj:TBaseGraphObject; // объявление <=> созание объекта в памяти
Begin
 obj.Init;  // конструирование объекта
 obj.Draw;    // использование свойств и (или) методов
 ...
End;

и динамические:
Код

Var
 obj:PBaseGraphObject;  // только объявление. Объекта в памяти еще не существует!
Begin
 obj:=New(PBaseGraphObject,Init);  // создание и конструирование объекта
 obj^.Draw;    // использование свойств и (или) методов
 ...
 Dispose(Obj); // после использования объекта, его нужно удалить из памяти
End;

помните нашего "вандала"-пользователя, который чего хочет то и творит? Если в первом случае, он забудет вызвать конструктор, то получится то, о чем я говорил выше - там где ..."раз и Draw"..., то во втором случае до создания объекта процедурой New, его использовать (объект) не получится, в памяти то его еще нет и работать с ним естественно нельзя. А при выделении памяти объекту можно взывать сразу и конструктор: obj:=New(PBaseGraphObject,Init), таким образом наш пользователь попал в ловушку - неправильно использовать объект в этом случае он просто не в состоянии
Автор: SPrograMMer






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

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную