16840

Объектно-ориентированное программирование. Методология объектно-ориентированного программирования

Лекция

Информатика, кибернетика и программирование

Объектно-ориентированное программирование. Основные понятия Методология объектно-ориентированного программирования Фундаментальными понятиями в программировании являются: технология программирования методология метод. Технология программирования...

Русский

2015-01-19

362 KB

7 чел.

Лекция 12

Объектно-ориентированное программирование

1. Основные понятия

Методология объектно-ориентированного программирования

Фундаментальными понятиями в программировании являются: технология программирования, методология, метод. Технология программирования (programming technology, sofware engineering) - это совокупность методов, способов и приемов разработки, сопровождения и применения программ, а также описание методов программирования. Метод - это совокупность приемов и операций практического и теоретического освоения действительности, в том числе программирования.

Любая технология программирования базируется на некоторой методологии разработки программ. Методология - это система принципов и способов организации и построения теоретической и практической деятельности, а также учение об этой системе.

Целью методологии программирования является изучение и внедрение таких методов проектирования и реализации программ, которые облегчают задачу сопровождения программы. Легкость сопровождения - это одно из тех качеств программы, которые нельзя добавить к программе после ее разработки.

В настоящее время широкую известность приобрели методы: структурного программирования, модульного программирования, объектно-ориентированного программирования (ООП), формализованных технических заданий и др.

Программа - это средство, для которого в результате опытного внедрения и дополнительных испытаний определена наиболее эффективная область применения, отработана методика внедрения и использования. Программное обеспечение (ПО, software) - это совокупность программ системы определенной обработки данных и программных документов, необходимых для эксплуатации этих программ.

Эволюция языков программирования для разработки программ - естественный процесс. Две важные тенденции эволюции:

  1.  создание надежного ПО: за счет контроля типов и успешности выполнения
    определенных действий;
  2.  в  языки  программирования  все  больше  проникают  средства  разработки
    программ, самого процесса их создания.

Эти средства рассредоточивают проектирование программ. При этом структура системы отделена от реализации ее компонентов; данные инкапсулируются с помощью абстрактных типов данных, что отделяет их реализацию от их описания. Такому расчленению разработки системы соответствуют модульное и ООП. Эта тенденция отражается на макроуровне языков введением понятий "модуль", "класс", "объект", "спецификация", "процесс".

Модульное и ООП - современные направления развития программирования. ООП - это новый этап развития современных концепций построения языков и систем программирования. В нем получили дальнейшее развитие принципы структурного программирования: структуризация программ и данных, модульность и пр. Традиционный подход к разработке программ не теряет своего значения. Но введение объектных типов достаточно радикально изменяет подход к программированию.

В основе ООП лежит понятие объекта (object). Объект - это тип, который включает не только поля данных объекта, но и подпрограммы для их обработки, называемые методами. Таким образом, в объекте сосредоточены его свойства (состояния, данные) и их поведение (обработка с помощью методов). Идеи создания нового типа (объект) были заложены при введении процедурных типов параметров.

ООП характеризуется тремя основными свойствами: инкапсуляцией (encapsulation), наследованием (inheritance) и полиморфизмом (polymorphism).

Инкапсуляция означает объединение в одном объекте данных и действий над ними.

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

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

Полиморфизм - это возможность определения единого по имени действия (процедуры или функции), применимого ко всем объектам иерархии наследования; причем каждый объект иерархии может иметь особенность реализации этого действия (например, движение точки, линии, окружности или различных фигур). Полиморфизм означает, что для различных родственных объектов можно задать единый класс действий (например, перемещение по экрану любой геометрической фигуры). Затем для каждого конкретного объекта составляется своя подпрограмма, вызывающая это действие для данного объекта (определенной геометрической фигуры); причем все подпрограммы, определяющие конкретный объект (и его фигуру), могут иметь одно и то же имя.

Особенности и применимость объектно-ориентированного программирования

Объектно-ориентированный подход к программированию имеет 4 важных аспекта:

1) модульность; она позволяет:

разбить программу на модули и локализовать область действия подпро
грамм и переменных;

изменять локальные подпрограммы, не изменяя других программных моду
лей;

  1.  абстракция данных; абстрактный тип данных определяется на основе неко
    торого их представления и множества подпрограмм для обработки данных
    абстрактного типа;
  2.  динамическая связка подпрограмм программы; это позволяет не переком
    пилировать всю программу при внесении изменений в отдельные модули,
    что увеличивает гибкость языка, позволяя вводить новые классы объектов
    без модификации всей программы;
  3.  наследование; оно позволяет создавать классы объектов, на которые может
    ссылаться  порожденный  класс,  который  наследует  все  свойства  порож
    дающего класса и может задавать дополнительные свойства и новые под
    программы обработки данных порожденного класса.

Это позволяет создавать компактные программы: при определении нового объекта, незначительно отличающегося от объекта-предка, не надо заново описывать свойства, общие с объектом-родителем, достаточно определить только различия.

ООП обладает рядом преимуществ при создании больших программ:

  1.  использование  более  естественных понятий  и  простота  введения  новых
    понятий;
  2.  некоторое сокращение размера программ за счет того, что повторяющиеся
    (наследуемые)  свойства   и  действия   можно   не   описывать   многократно;
    применение динамических объектов позволяет более эффективно использовать ОП;
  3.  возможность создания библиотек объектов;
  4.  сравнительно простая возможность внесения изменений в программу без
    изменения написанных частей, а в ряде случаев без перекомпиляции написанных и скомпилированных программ (библиотек); при этом используются свойства наследования  и полиморфизма;  это упрощает модификацию программ, придает им гибкость; одно из главных достоинств ООП - возможность расширять область применения программ, не переделывая программу, а лишь добавляя в нее новые уровни иерархии;
  5.  возможность  использования  подпрограмм  с  различными  наборами  формальных параметров, но имеющих одно и то же имя, применяя свойство
    полиморфизма;
  6.  более четкая локализация свойств и методов объекта (с помощью свойства
    инкапсуляции);

возможность разделения доступа к различным объектам программы.

Однако ООП имеет ряд недостатков и эффективно не всегда.

ООП требует изучения большого количества встроенных подпрограмм объектов порождающих классов.

Как правило, использование ООП приводит к уменьшению быстродействия программы, особенно когда применяются виртуальные методы. Неэффективно ООП применительно к небольшим программам. Преимущества ООП в полной мере проявляются только при разработке достаточно сложных программ. Поэтому ООП можно рекомендовать при создании больших программ или класса программ, например для создания интерактивных систем с помощью средств визуального программирования. Применение ООП не упрощает саму программу, а упрощает технологию ее создания.

Попытки использовать ООП для программирования несложных алгоритмических действий, связанных, например, с вычислениями по готовым формулам, чаще всего выглядит искусственным нагромождением ненужных языковых конструкций. Их проще разрабатывать традиционными средствами Паскаля. А при разработке сложных диалоговых программ программист вынужден структурировать программу, т. е. разбить ее на ряд взаимосвязанных и взаимозависимых подпрограмм. Это фактически ведет к разработке собственной библиотеки подпрограмм; в этом случае целесообразно использовать средства ООП.

2. Свойства объектов

Инкапсуляция

Определение объекта

Основным понятием ООП и элементом программ является объект. Любая объектно-ориентированная программа состоит из двух частей:

  1.  декларативной части программы (описания объектов);
  2.  исполняемой части программы (основной программы и подпрограмм).

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

Объединение декларативных (данных) и исполняемых (процедурных) элементов при описании объекта называется инкапсуляцией.

Объект - это такая структура, компонентами которой являются данные и методы (процедуры и функции) для их обработки. Компоненты - данные -это поля объекта, а компоненты подпрограммы - это методы. По написанию объект напоминает тип-запись. Форма объявления объекта:

TYPE Имя-объекта = OBJECT

Поля-данных;

Заголовки-методов;

END;

При описании объекта сначала определяются все данные объекта, а затем -заголовки методов их обработки - как опережающие описания подпрограмм. Далее - тексты всех методов, написанные так же, как подпрограммы в модулях. Методы всегда используют дальний тип вызова независимо от состояния директивы $F.

Текст подпрограммы метода может быть в одном из программных файлов: в том же, где объявлен объект, или в другом, например в одном из модулей. При написании текста метода в заголовке подпрограммы перед ее именем обязательно надо указать имя типа объекта, которому принадлежит метод, т. е. имя метода должно быть составным в виде: имя-типа-объекта.имя-подпрограммы;.

Конкретная переменная или константа объектного типа называется экземпляром - переменною или константою этого типа. Вызов метода для обработки данных экземпляра состоит из составного имени в виде: имя-экземпляра-объектного-типа   .   имя-метода;

Пример программы с объявлением объекта и его использованием приведен в листинге 1.

Листинг 1. Объявление и использование экземпляров объектного типа.

Program Ex1;

Type  ObName = object  { - начало объявления объекта } Fl1 : integer;

  Fl2 : real;

Procedure MetName( Param1 : integer; Param2 : real) ;

end; { - конец  объявления объекта }

Procedure ObName.MetName;

Begin  Fll := Param1;

F12 := Param2;

End; { Объявление и инициализация экземпляра -

типизированной константы объектного типа: }

Const ObCon : ObName = ( Fl1 : 5; Fl2 : 2.5 );

{ Объявление экземпляра - переменной объектного типа :}

Var  ObVar : ObName;

Begin 

{ Вывод значения объектной константы с помощью составного имени: }

Writeln ('ObCon.Fl1= ', ObCon.Fll);

{ Присоединение к экземпляру объектной константы: }

With ObCon do Writeln ('Fl1 = ',Fl1,'F12 = ',F12:10);

ObVar.MetName ( 7, 3.8 ); { - вызов метода }

{ Вывод значения объектной переменной с помощью составного имени: }

Writeln ( 'ObVar.Fl1 = ', ObVar.Fll);

{ Присоединение к экземпляру объектной переменной: }

With ObVar do  Writeln ('Fl1 = ',Fl1,'F12= ',F12:10);

End.

В программе объявлены:

ObName - объектный тип . Он содержит 2 элемента (поля):

Fl1 - типа integer;

Fl2 - типа real.

В состав объекта входит MetName - метод инициализации значений экземпляра объекта данного типа.

Область действия полей объекта и параметр SELF

Принципы ООП требуют, чтобы прямые обращения к полям объекта в тексте основной программы производились как можно реже, обращение к полям предпочтительно только из доступных им методов. Таким образом, в основной программе должны быть только вызовы методов, изменяющих поля.

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

При обращении к методу ему передается особый системный идентификатор SELF (свой, внутренний), представляющий собой обобщенное имя конкретного экземпляра объекта. Внутри методов объекта действует неявный оператор WITH экземпляра (SELF). Это обеспечивает обработку данных именно этого конкретного экземпляра объектного типа. Для объектов допустим и явный With.

Так как область действия (domain) полей данных объекта распространяется на тела подпрограмм, реализующих методы данного объекта, имена формальных параметров методов (если они есть) не должны совпадать ни с одним из имен полей данных этого объекта.

Компилятор автоматически обрабатывает параметр SELF, поэтому не стоит использовать его явно. Исключением является случай, когда возникает "конфликт" между идентификаторами в пределах методов. Пример такой "развязки" приведен в листинге 2. В программе листинга 2 одинаковы имена элементов записи и полей объекта.

Листинг 2. Развязка конфликта имен.

Uses   Crt;

Type  PosRec = Record { - объявление записи  }

Line, Col : Word;    { - имена ее элементов }

end; {  - конец объявления записи }

ObjPos = OBJECT { - объявление объекта }

Line, Col : Word;    { - совпали имена полей объекта и записи }

Procedure Init ( Роs : PosRec );

end; { - конец объявления объекта }

{    Метод объекта ObjPos   }

Procedure ObjPos.Init ( Pos : PosRec );

Begin 

With Pos do begin  { - присоединение к формальному параметру }

{ поля  > } Self.Line := Line;{ <- поля записи с With для}

{ объекта : } Self.Col := Col; { формального параметра  }

end  { - With }

End;

{ Переменные типа: }

Var VObj: ObjPos;       { - объект }

VPosRec: PosRec;    { - запись }

{  Основная программа }

Begin ClrScr;

VPosRec.Line := 2;    { - инициализация полей записи } VPosRec.Col  := 5;

Writeln('Поля записи: ', #10#13,

'VPosRec.Line =', VPosRec.Line, { - вывод полей записи }

   ' VPosRec.Col = ', VPosRec.Col );

Writeln('Неинициализированные поля объекта:', #10#13,

'VObj.Line =', VObj.Line, { - вывод полей объекта }  ' VObj.Col    = ', VObj.Col    );

VObj.Init(VPosRec);  { - инициализация полей объекта данными записи }

Writeln('Инициализированные поля объекта:', #10#13,

'VObj.Line = ', VObj.Line, ' VObj.Col = ',VObj.Col    ); End.

Скрытые поля и методы

Часть полей и методов объектных типов можно объявить как скрытые. Это ограничивает область их видимости. Для этого используется ключевое слово private. Схема объявления:

Туре

ObjectType = object

Обычные поля и методы

private

Скрытые поля и методы

end;

Идентификаторы полей и методов, объявленных как скрытые, известны (доступны, видимы) только в пределах программы или модуля, в которых они объявлены. Вне модуля с их описанием скрытые поля и методы неизвестны (недоступны). Сам объектный тип и его остальные компоненты видимы по обычным правилам.

Скрытые компоненты объектных типов аналогичны переменным раздела реализации (implementation) модуля. Это позволяет изолировать (скрыть) технические подробности реализации объектов от программ-потребителей, способствует большей независимости программных единиц и служит дополнительным средством контроля за использованием объектов.

Наследование и переопределение. Принцип конструирования программ

ООП позволяет определить новый объект как потомок (наследник) другого, ранее определенного типа. Это означает, что новый тип автоматически получает все поля и методы ранее определенного типа, который в этом случае называется предком или родителем. В объявлении типа-потомка (наследника) должно быть указано в круглых скобках после служебного слова object имя родительского типа. Поля и методы предка могут появляться в телах методов наследников так, как если бы они были явно объявлены в объектах-наследниках. Это существенно упрощает запись схожих объектов.

Форма объявления объекта-потомка (наследника):

TYPE

Имя-типа-объекта-потомка =OBJECT(Имя-типа-объекта-предка)

             Новые-поля-объекта-потомка;

             Новые-методы-объекта-потомка;

END;

Предок у типа может быть только один. Он может быть потомком другого типа и т. д. Потомков у одного предка может быть много. Потомок наследует поля и методы всех своих предков.

Процесс наследования является транзитивным: если тип объекта ТуреВ -наследник типа ТуреА, а тип ТуреС - наследник типа ТуреВ, то тип объекта ТуреС также является наследником ТуреА:

Туре А → Туре   В → Туре  С

В потомках (производных, дочерних) нельзя объявлять идентификаторы полей, определенные в одном из типов предка. На методы это ограничение не распространяется.

Объект-потомок может переопределить любой из методов, наследуемый от предков. Метод, переопределенный в типе-потомке, имеет то же имя и может иметь другие параметры. Переопределенный метод переходит ко всем последующим потомкам иерархии. Для каждого потомка действует метод, определенный в нем самом или в ближайшем объекте-предке, если в данном объекте этот метод не переопределен.

Пример простой иерархической структуры приведен на рис. 1.

Наследование - самое мощное свойство ООП. Оно позволяет строить библиотеку по принципу "от простого к сложному". Такой принцип разработки программ называется восходящим программированием. Ввод с помощью наследования нового объекта в библиотеку позволяет максимально использовать ранее созданные объекты.

При использовании ООП рекомендуется сочетание двух принципов конструирования программ: нисходящего и восходящего программирования. Методами нисходящего программирования генеральный алгоритм расчленяется на ряд относительно крупных и законченных в смысловом отношении фрагментов (модулей). А реализация этих фрагментов может производиться с использованием ООП.

Основное применение ООП - это разработка библиотек определенного направления. Примером такого применения является VCL - Visual Component Library - библиотека компонентов системы визуального программирования Delphi.

Рис. 1

Пример простой иерархической структуры

Наследование имеет определенные правила совместимости типов объектов. При этом производный тип (тип-потомок) совместим по типу со своим предком:

между экземплярами объекта;

между указателями на экземпляры объектов;

между формальными и фактическими параметрами.

Совместимость имеет место только от потомка к предку. Другими словами, производные типы можно использовать вместо родительских, но не наоборот. Это определяет правила присваивания для переменных типа объект. Они состоят в том, что переменным можно присваивать значения этого же типа и любого производного от него, т. е. предку можно присвоить значение объекта-потомка. Обратное присваивание недопустимо. Производный тип всегда получается не меньшим, чем тип предка (родительский). В результате выполнения присваивания будут скопированы от источника только те поля, которые являются общими для обоих типов.

Полиморфизм

Основные понятия

Полиморфизм - это возможность иметь несколько методов с одним и тем же именем для различных объектов одной иерархии, т. е. средство для развития объектов в потомках. Оно реализуется тем, что объект-потомок может переопределять, т. е. заменять методы предка на новые с теми же именами. Какой из методов будет выполняться при. обращении к методу с заданным именем, определяется типом объекта (предок или потомок) и используемого метода.

Методы объектов по способам их переопределения могут быть статические, виртуальные и динамические (подкласс виртуальных). В соответствии с этим процесс установки взаимосвязи объектов и методов может быть:

ранним - во время компиляции - для статических методов;

поздним - во время выполнения программы (вызова метода) для виртуаль
ных методов.

Статические методы

По умолчанию все методы статические. Все ранее рассмотренные методы -статические. Такое наименование методов связано с тем, что определение и размещение ссылок на них (для вызова методов) производится на этапе компиляции и на все время выполнения программы. Это - раннее связывание.

Список формальных параметров статических методов может быть различным у метода предка и методов потомков, переопределяющих (заменяющих) этот метод предка.

Со статическим методом связан способ наследования. Если в объявлении потомка появляется метод с тем же именем, что и у предка, то в этом типе и во всех его потомках этот метод будет переопределен. Таким образом, потомки могут использовать переопределенные ими методы предка. Предок может вызвать только свои методы; методы потомков для него недоступны. Таким образом, при использовании статических методов полиморфизм распространяется от текущего уровня иерархии вниз, к потомкам.

Действия компилятора при обработке методов иерархии объектов для статических методов:

  1.  при вызове метода компилятор устанавливает тип объекта, вызывающего
    метод;   
  2.  затем он ищет метод в пределах этого типа; найдя его, компилятор назначает вызов этого метода;
  3.  если метод не найден, то компилятор рассматривает тип непосредственно
    го предка и ищет метод в его объявлении:

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

б) если метод не найден в типе ближайшего предка, компилятор переходит
к типу предка, следующего в иерархии предков; и так до тех пор, пока
не будет найден вызванный метод;

в) если компилятор, дойдя до верхнего уровня иерархии, не найдет метод,
он выдаст сообщение об ошибке номер 44 периода компиляции:

Field  identifier  expected - ожидается идентификатор поля.

Это сообщение выдается, если идентификатор не соответствует имени поля переменной типа RECORD или типа OBJECT.

Существенное ограничение статических методов: если метод предка вызывает другие методы, то это могут быть только методы предка, даже если потомок имеет свои собственные методы с таким же именем метода. Этот недостаток предопределен тем, что связь объекта с методом производилась на этапе компиляции, статически, на все время выполнения программы. Этот недостаток статических методов устраняется использованием виртуальных методов.

Ограничение статических методов рассмотрим на примере программы листинга 3. Из него видно существенное ограничение статических методов: если метод (Metl объекта ObjName1) предка вызывает другие методы (Met2), то это могут быть только методы предка (objNamel .Met2), даже если потомок имеет свои собственные методы с таким же именем метода (objName2 .Met2). В примере листинга 3 оператор V2.Metl; вызывает выполнение метода ObjNamel .Metl, который вызывает метод ObjNamel .Met2, несмотря на то что тип ObjName2 имеет свой собственный метод ObjName2 .Met2. Это происходит потому что связь объекта с методом производилась на этапе компиляции. Схематично это представлено на рис. 2.

Листинг 3. Вызовы статических методов предка и потомка.

Program novirt1;   Uses Crt;

Type ObjName1 = object    { - объявление объекта-предка } Fl1 : integer;    { - поле }

   Procedure Met1;   { - методы }

   Procedure Met2;

   End;

ObjName2 = object (ObjName1)   { - объявление потомка } Procedure Met2;        { - замена статического метода } End;

{   Методы объекта ObjName1   }

Procedure ObjName1.Met1;

Begin Met2;   { - вызов только метода ObjName1.Met2 !!} End;

Procedure ObjName1.Met2;

Begin        FL1 := 12;

Writeln ( 'Работает метод ObjName1.Met2: FL1 = ', FL1) End;

{    Метод объекта ObjName2   }

Procedure ObjName2.Met2; Begin       FL1 := 34;

Writeln ( 'Работает метод ObjName2.Met2: FL1 = ', FL1) End;

Var VI:ObjName1; { - переменная объектного типа - предка  }
V2 : ObjName2;   { -     " "      "    
потомка }

{  - Основная программа   }

Begin        ClrScr;

Assign (Output, 'Inovirt.res'); Rewrite (Output);

Writeln ( 'ОБЪЕКТЫ, СТАТИЧЕСКИЕ МЕТОДЫ1 );

Writeln ('Работаем с VI - экземпляром типа предка');

VI.Met1; {- вызывается метод Met1 для экземпляра VI - предка }

{  Met1 вызывает метод ObjName1.Met2 - предка }

V1.Met2;  { - непосредственно вызывается метод ObjName1.Met2; }

Writeln ('Работаем с V2 - экземпляром типа потомка');

V2.Met1;  { - вызывается метод Met1 для экземпляра V2 - потомка; Met1 вызывает метод ObjName1.Met2 - предка, а не ObjName2.Met2 - потомка - в этом - ограничение }

V2.Met2   { - непосредственно вызывается метод ObjName2.Met2; }

Close (Output);

End.

Рис. 2

Схема ограничения вызова переопределенных статических методов

Виртуальные методы. Конструкторы

Виртуальный   (кажущийся,   гипотетический)   метод   имеет   спецификатор (стандартную директиву) Virtual. Например:

Procedure Met2;   Virtual;

Виртуальный метод предназначен для переопределения виртуального метода предшествующего предка. Недопустимо смешение статических и виртуальных методов при их переопределении. Ограничение: переопределяющие виртуальные методы должны иметь точно такой же набор формальных параметров, как и самый первый виртуальный метод многоуровневой иерархии объектов.

Паскаль обеспечивает вызов (связывание) виртуального метода программы на этапе выполнения программы. Это называют поздним связыванием. При позднем связывании полиморфизм распространяется не только от текущего уровня иерархии вниз, к потомкам (как для статических методов), но и вверх, к предкам.

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

  1.  если для экземпляра потомка методы предка вызывают другие виртуальные
    методы, имена которых есть в объекте-предке и в объекте-потомке, то вы
    зываются методы потомка;
  2.  виртуальные методы используют позднее связывание данных с методами,
    с помощью которых они будут обрабатываться, т. е. связывание на этапе
    выполнения программы.

Компилятор не устанавливает связи объекта с виртуальным методом. Вместо этого он создает специальную таблицу виртуальных методов (ТВМ, VMT -Virtual Method Table). Для каждого типа объекта создается своя ТВМ; каждый экземпляр объекта использует эту ТВМ, единственную для данного типа виртуальных объектов. В каждой ТВМ содержится размер данного типа объекта в байтах. ТВМ любого объекта доступна через скрытый параметр Self, содержащий адрес ТВМ, который передается методу при вызове.

Связывание каждого экземпляра объекта и его ТВМ осуществляется с помощью конструктора на этапе выполнения программы. Это специальный метод, подобный обычной процедуре, но в заголовке вместо PROCEDURE стоит слово CONSTRUCTOR. Если объектный тип содержит виртуальный метод, то он должен содержать хотя бы один конструктор. Каждый экземпляр объекта должен инициализироваться отдельным вызовом конструктора. Конструктор инициализирует экземпляр объекта и устанавливает для него значение адреса его ТВМ. Экземпляр объекта содержит только адрес ТВМ, а не саму ТВМ.

Вызов конструктора должен предшествовать вызову любого виртуального метода для обработки данного экземпляра объекта. Обращение к виртуальному методу до вызова конструктора вызовет ошибку на этапе выполнения программы, так как нет связи экземпляра объекта с его ТВМ.

При отладке программы можно использовать директиву компилятора {$R+}. При этом компилятор будет проверять, инициализирован ли экземпляр объекта, вызывающий виртуальный метод. Если в процессе проверки инициализации экземпляра объекта, вызывающего виртуальный метод, будет обнаружен вызов метода до инициализации объекта конструктором, выдается сообщение о фатальной ошибке 210:

Object not initialized - объект не инициализирован.

Так как директива {$R+} замедляет выполнение программы, после отладки директиву надо удалить; по умолчанию работает директива {$R->.

В объекте может быть сколько угодно конструкторов. Конструктор не может быть виртуальным. Конструктор может быть только статическим и может быть переопределен. Конструкторы наследуются так же, как и другие статические методы. Из конструктора можно вызывать и виртуальные методы.

Метод конструктора может быть и пустым, так как основная информация содержится не в теле конструктора, а связана с его заголовком, содержащим слово Constructor. Например:

Constructor TA.TNIT ;

Begin

End;

Конструктору принято давать имя INIT. На практике в качестве конструктора используют метод, который устанавливает некоторые начальные значения экземпляра объекта. В конструкторе может происходить выделение ОП из кучи, если поля данных динамические, и необходимая инициализация полей данных (в том числе и вызовы конструкторов-предков для унаследованных полей).

Пример программы с использованием виртуальных методов дан в листинге 4. Это вариант программы листинга 3, но с виртуальным методом Met2.

Листинг 4. Использование виртуальных методов.

Program virt1;    {$F+,R+}         Uses Crt;

Type ObjName1 = object   { - объявление объекта-предка } Fl1 : integer;

Constructor Met1; { - конструктор      }

Procedure Met2; Virtual;   { - виртуальный метод } End; ObjName2 = object(ObjName1){- объявление потомка}

Procedure Met2; Virtual;   { - виртуальный метод } End;

{    Методы объекта ObjName1   }

Constructor ObjName1.Met1; Begin  Fl1 := 12;

Met2; { - вызов Met2 из конструктора }

End;

Procedure ObjNamel.Met2;

Begin

Writeln ( 'Работает метод ObjName1.Met2: FL1 = ', Fl1) End;

{    Методы объекта ObjName2   }

Procedure ObjName2.Met2; Begin     Fl1 := 34;

Writeln ( 'Работает метод ObjName2.Met2: FL1 = ', Fl1) End;

Var VI:ObjName1;{- переменная объектного типа - предка  }
V2 : ObjName2;   { -     " "      "    
потомка }

{  Основная программа  }

Begin ClrScr;

Assign (Output, '2virt.res'); Rewrite (Output);

Writeln ( 'ОБЪЕКТЫ, ВИРТУАЛЬНЫЕ МЕТОДЫ' );

Writeln ('Работаем с VI - экземпляром типа предка'); VI.Met1; { - вызывается конструктор Met1 для экземпляра VI - предка }

{   Met1 вызывает метод ObjName1.Met2 - предка }

VI.Met2; { - непосредственно вызывается метод ObjName1.Met2; }

Writeln ('Работаем с V2 - экземпляром типа потомка'); V2.Met1; { - вызывается конструктор Met1 для экземпляра V2 - потомка VI; Met1 вызывает метод ObjName2.Met2 - потомка -в этом достоинство виртуальных методов }

V2.Met2  { - непосредственно вызывается метод ObjName2.Met2;    }

Close. (Output) ;

End.

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

Var  Obj1, Obj2 : TObj;  { - объявление переменных } Begin

Obj1.Init;    { - инициализация Obj1 }

Obj2 := Obj1; { - недопустимо до инициализации Obj2

с помощью Obj2.Init; }

End.

Хорошим стилем ООП является использование процедур инициализации предков. То есть если потомок имеет новую процедуру инициализации, то в ней обычно сначала вызывается процедура инициализации (например, конструктор) непосредственного предка, а затем выполняется своя. Это естественный способ проинициализировать наследуемые поля предназначенным для этого методом.

Дополнительная возможность вызова метода, непосредственно наследуемого объектом-потомком, - использование ключевого слова Inherited (наследуемый) перед именем вызываемого метода. Например, Objl непосредственный предок объекта Obj2. В состав Objl входит метод Metl. Вызов этого метода объекта Objl из метода Obj2.Met2 может быть задан явно в виде:

Procedure Obj2.Met2;

Begin  Inherited Met1 (A1, A2);

{ Это эквивалентно вызову: Obj1.Met1 (A1, A2); }

End;

При этом не надо знать имя объекта-предка (Objl). Основные правила использования виртуальных методов:

1) если тип объекта-предка описывает метод как виртуальный, то все его потомки, которые реализуют свой метод с тем же именем, должны описать
этот метод как виртуальный. Нельзя виртуальный метод заменить статическим. Иначе компилятор выдаст сообщение об ошибке:

Error 149: VIRTUAL expected - ОЖИДАЕТСЯ СЛОВО VIRTUAL.

2) если переопределяется виртуальный метод, то заголовок переопределяемо
го метода не может быть изменен; должны остаться неизменными: количество, последовательность и типы формальных параметров в одноименных
виртуальных методах. Если этот метод - функция, то не должен изменяться и тип результата. При нарушении этого правила компилятор выдаст сообщение:

131:   Header  does  not match previous  definition  - заголовок не соответствует предыдущему определению;

  1.  в описании объекта, имеющего виртуальные методы, обязателен -конструктор. Он устанавливает работу механизма виртуальных методов. Вызов виртуального метода без предварительного вызова конструктора может при
    вести к тупиковому состоянию. Чтобы избежать этого, на период отладки
    надо включить директиву компилятора {$
    R+};
  2.  каждый экземпляр объекта должен инициализироваться отдельным вызовом конструктора;
  3.  количество конструкторов может быть любым;
  4.  конструктор должен быть статическим и может быть переопределен.

Динамические методы

В Паскале имеется дополнительный класс методов позднего связывания -динамические методы. Они являются подклассом виртуальных методов и отличаются от них только способом вызова на этапе выполнения.

Объявление динамического метода аналогично виртуальному, за исключением того, что оно должно включать индекс (номер) динамического метода, который указывается сразу за ключевым словом Virtual. Индекс динамического метода должен быть целочисленной константой в диапазоне от 1 до 65535 и представлять собой уникальное значение среди индексов других динамических методов данного объектного типа и его предков. Например:

Function  GetSum:   Real;   Virtual   10;        где - 10 - ИНДЕКС.

Переопределение динамического метода аналогично переопределению виртуального. Оно должно включать слово Virtual, за которым следует тот же индекс, что и в переопределяемом динамическом методе предка.

Использование динамических методов целесообразно при создании длинной иерархии объектов с большим количеством виртуальных методов. Если не использовать динамические методы, для них создаются длинные таблицы виртуальных методов с указанием всех виртуальных методов-предков, хотя переопределяться может только часть из них. Это требует большого объема ОП.

При использовании динамических методов создается таблица динамических методов (ТДМ, DMT - Dynamic Method Table), альтернативная таблице виртуальных методов. В ней указываются только те виртуальные методы, которые переопределяются. Это экономит ОП, но требуется время для поиска в DMT объектов-предков. Поэтому производительность DMT ниже, чем VMT, так как доступ к методу через VMT - простое извлечение адреса из таблицы, а доступ к методу через DMT может привести к более длительному поиску.

Выбор типа метода

Прежде чем разрабатывать программу с использованием ООП, надо разработать иерархию типов. Определяя иерархию типов, надо собрать все общие атрибуты, в один тип-предок и позволить остальным типам иерархии наследовать все общие элементы этого типа.

При выборе типа метода, статического или виртуального, можно использовать следующее правило: если есть хотя бы малейшая вероятность того, что понадобится из метода предка вызов переопределенного метода потомка, целесообразно делать метод виртуальным.

Преимуществом использования виртуальных методов является то, что типы объектов и методы можно определить в модуле и поставить пользователю модуль в виде TPU-файла. Для работы с объектами модуля надо знать содержимое только интерфейсной части модуля. Используя полиморфные объекты и виртуальные методы, пользователь TPU-файла может добавлять новые методы к уже существующим.

Добавление новых функциональных характеристик в программу без модификации ее исходного кода (текста) называют способностью к расширению. Это - результат наследования. Позднее связывание позволяет связать новые методы с существующими во время выполнения программы, требуя лишь небольшого увеличения ТВМ.

Не следует сомневаться в том, включать или не включать в объект метод, который может быть использован или не использован в конкретной программе. Неиспользуемые методы не влияют ни на быстродействие программы, ни на размер ЕХЕ-файла: если они не используются, то они не включаются в него.

В общем случае рекомендуется делать методы виртуальными. Но они требуют ОП для ТВМ. Кроме того, каждый вызов виртуального метода проходит через ТВМ и требует для этого дополнительное время. Использование статических методов имеет смысл, если надо получить оптимальную эффективность программы по скорости ее выполнения и использованию ОП. Статические методы вызываются непосредственно. Поэтому вызов статического метода более быстрый, чем вызов виртуального. Если в объекте нет виртуальных методов, в сегменте данных отсутствует ТВМ и программа будет работать быстрее. Однако в этом случае теряется вариант расширения возможностей на этапе выполнения программы, при позднем связывании.

3. Динамические объекты

Основные понятия

По способам размещения экземпляров объектов в ОП они могут быть, как и другие переменные, статическими или динамическими.

Все приведенные до сих пор объекты были статическими. Они были объявлены в разделе VAR, имели имена и размещались в сегменте данных или в стеке (локальные объекты). ОП для них выделялась до начала выполнения программы. Так же как и любые типы данных в Паскале, объекты могут быть динамическими и размещаться в куче. Работа с динамическим объектом аналогична работе с динамической переменной: надо объявить указатель на объект, создать динамический объект (с выделением ему ОП), обработать и удалить (с освобождением выделенной ОП).

После создания динамических объектов с помощью процедуры или функции New значения указателей и динамических переменных можно использовать, например, в операторах присваивания:

PObjl   :=  PObj2; - копирование указателя на объект;

Pobjl^   :=  PObj2^; - копирование полей динамического объекта.

Создание динамических объектов

Для того чтобы сформировать динамический объект, надо объявить соот ветствующий тип OBJECT и указатель на этот тип. Например:

Type  ObjName = Object       { - тип - ObjName }

. . .

End;  

PObjName = ^ObjName;  { - тип - указатель на ObjName } {  Объявление динамического объекта:

Var  PI : PObjName;  { - со ссылкой на тип - указатель на объект}

Р2 : ^ObjName;  { - со ссылкой на тип - объект }

Создание динамического объекта, содержащего только статические методы, производится с помощью процедуры или функции NEW, а уничтожение такого динамического объекта - с помощью процедуры DISPOSE.

Простейший способ размещения и удаления из ОП таких динамических объектов:

New ( P1 ); New ( Р2 );  ... Dispose ( P1); Dispose ( P2 );

где     P1 и Р2 - имена указателей на динамические объекты.

New может использоваться также в качестве функции, которая возвращает значение указателя. Например:

P1 := New ( PObjName );

где     PobjName - имя типа указателя динамического объекта.

Обращение к переменной - экземпляру объекта с помощью указателя производится в виде Р1^ или Р2^.

Вызовы методов производятся обычным способом. Например: Р1^.МЕТ2;

Если динамический объект содержит виртуальные методы, он должен инициализироваться с помощью вызова конструктора. Например:

Pl^.INIT; P2^.INIT;

Если конструктор не может разместить динамический объект в ОП, то он возвращает "пустой" указатель, например: PI = NIL.

Для работы с динамическими объектами, содержащими виртуальные методы, Паскаль имеет процедуры NEW и DISPOSE с расширенными возможностями. Расширенный синтаксис процедуры New позволяет выделять из кучи ОП для объекта и инициализировать сам объект с помощью вызова его конструктора. Для этого процедура New вызывается с двумя параметрами: именем указателя и именем конструктора. Например:

New (P1,INIT);  New(P2,INIT);.

Параметр INIT выполняет вызов конструктора и инициализацию динамического объекта.

Пример программы, использующей динамические объекты с виртуальным методом, приведен в листинге 6.

Удаление динамических объектов. Деструкторы

Динамическими могут быть объекты со статическими и виртуальными методами. Удаление динамических объектов может быть с помощью процедур Dispose или с помощью деструктора.

Подобно другим динамическим типам данных динамические объекты со статическими методами могут удаляться с помощью Dispose. Например:

Dispose ( P1 );.

Пример программы с динамическим объектом со статическими методами дан в листинге 5.

Листинг 5. Динамические объекты со статическими методами.

Program novirt;        Uses Crt;     { Объявления:      }
Type  ObjName1 = object { -
объекта-предка }

Fl1 : integer;

Procedure Met1;

Procedure Met2; End;

ObjName2 = object ( ObjName1 )  { - объекта-потомка }

Procedure Met2; End;

PobjName1 = ^ObjName1; {-тип - указатель на объект ObjName1 }

PObjName2 = ^ObjName2;  { -  "  "  "   "   ObjName2 }

{   Методы объекта ObjName1   }

Procedure ObjName1.Met1; Begin

Met2; { - вызов только метода ObjName1.Met2 !!}

End;

Procedure ObjName1.Met2; Begin        FL1 := 12;

Writeln ( 'Работает метод ObjName1.Met2: Fl1 = ', FL1) End;

{    Методы объекта ObjName2   }

Procedure ObjName2.Met2; Begin       FL1 := 34;

Writeln ( 'Работает метод ObjName2.Met2: Fl1 = ', FL1) End;

Var V1 : PobjName1;       { - динамический объект V1 } V2 : PObjName2;        { -      "         "    V2 }

{  Основная программа }

Begin ClrScr;

Assign (Output, 'dnovirt.res'); Rewrite (output);

Writeln ('ДИНАМИЧЕСКИЕ ОБЪЕКТЫ, СТАТИЧЕСКИЕ МЕТОДЫ'); Writeln ('Работаем с VI - экземпляром типа предка');

New ( V1 ); { - создание динамического объекта V1 }

V1^.Met1; { - вызов метода ObjName1 .Met1; }

Vl1.Met2; { -   "     "    ObjName1.Met2; }

Dispose ( V1 );      { - удаление объекта V1 }

Writeln ('Работаем с V2 - экземпляром типа потомка');

New ( V2 ); { - создание динамического объекта V2 }

V2^.Met1; { - вызывает ВСЕГДА метод ObjName1.Met2,

а не ObjName2.Met2 }

V2^.Met2; { - вызов метода ObjName2.Met2; }

Dispose ( V2 );      { - удаление объекта V2 }

Close (Output);

End.

Для освобождения ОП динамических объектов с виртуальными методами используются особые методы - деструкторы. В качестве их имен рекомендуется употреблять имя Done. Они предназначены для выполнения завершающих действий программы. Деструктор размещается вместе с другими методами объекта в определении типа и оформляется так же, как обычный метод-процедура, но слово PROCEDURE заменяется словом DESTRUCTOR. Например: Destructor TObjl.Done;.

Вызов деструктора (Done) вне процедуры Dispose не приведет к автоматическому освобождению ОП, занимаемой экземпляром объекта, т. е. недопустимо Р1^.Done;.

Для корректного освобождения ОП, которую реально занимает экземпляр динамического объекта с поздним связыванием, деструктор надо вызывать с помощью расширенного типа процедуры Dispose. Он имеет 2 параметра: имя указателя на объект и имя деструктора. Например:

Dispose ( PI,Done);

где     Done - имя деструктора объекта, на который указывает Р1.

Деструктор выполняется как обычный метод. Когда будет выполнено последнее его действие, если объект содержит виртуальные методы, то деструктор производит поиск размера объекта в ТВМ и передает его процедуре Dispose, которая и освобождает правильное количество байт, независимо от того, указывал ли Р1 на тип предка или потомка.

Метод деструктора может быть и пустым, так как основная информация содержится не в теле деструктора, а связана с его заголовком, содержащим слово Destructor.

Деструктор потомка последним своим действием должен вызывать соответствующий деструктор своего непосредственного предка, чтобы освободить ОП всех наследуемых указателей объекта. Например:

Destructor Tobj1.Done;

Begin

. . .   INHERITED Done;

End;

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

Термин "полиморфный" означает, что компилятор, строя код объекта, во время компиляции, "не знает", какой тип объекта будет в действительности использован. Единственное, что он "знает", - это то, что объект принадлежит иерархии объектов, являющихся потомками указанного типа предка. Размеры различных объектов иерархии могут быть разные. Информация о размере удаляемого объекта становится доступной, для деструктора из ТВМ в момент удаления экземпляра объекта. ТВМ любого объекта доступна через параметр Self, содержащий адрес ТВМ, который передается деструктору при его вызове.

Деструктор может объединять удаление объекта с другими действиями, необходимыми для корректного удаления. Например, при удалении динамического объекта может понадобиться не только освобождение занимаемой им ОП. Объект может содержать указатели на динамические объекты или связанные структуры (стеки, очереди, списки), которые надо удалить в определенном порядке. Все операции для удаления динамического объекта должны объединяться в один метод, чтобы объект мог быть уничтожен с помощью одного вызова. Например: Objl .Done; или Dispose ( Pi, Done );.

Для одного и того же типа объекта может быть несколько деструкторов. Деструкторы можно наследовать. Они могут быть статическими или виртуальными. Например: Destructor Done; Virtual;

Для динамических объектов целесообразно объявлять виртуальный деструктор, даже если объект не содержит других виртуальных методов. Если деструктор виртуальный, связь с конкретным экземпляром объекта осуществляется в процессе выполнения программы. Следовательно, в зависимости от типа экземпляра объекта деструктор будет обращаться к ТВМ-предка или к ТВМ-потомка иерархии объектов. Размеры выделяемой для них ОП могут быть разными. При этом для каждого типа объекта выполняется деструктор, соответствующий данному типу объекта.

Деструкторы работают с динамическими объектами. Но применение деструктора к статическим объектам не является ошибкой и не приведет к некорректной работе программы.

Пример программы с динамическим объектом с виртуальными методами и с использованием деструктора приведен в листинге 6.

Листинг 6. Динамические объекты с виртуальным методом.

Program Dvirt;        {$F+,R+} Uses   Crt;

Type     ObjName1  =  object { - тип  объекта-предка   }

Fl1   :   integer;

Constructor Met1; {-  конструктор  типа  ObjName1 }

Destructor  Done; Virtual; {- деструктор типа  ObjName1 } Procedure  Met2;   Virtual; End;

ObjName2=object (ObjName1) {-тип потомка ObjName1 ) Procedure Met2;   Virtual;

Destructor Done; Virtual; {-деструктор типа  ObjName2 } End;

PobjName1 = ^ObjName1; {- тип - указатель на объект  ObjName1}
PObjName2  = ^ObjName2;  { -" " "       ObjName2   }

{         Методы объекта  ObjName1       }

Constructor ObjName1.Met1; Begin

Met2; {-   вызов  Met2   из   конструктора   }

End;

Destructor  ObjName1.Done; Begin

Writeln   ('Освобождается  ОП  объекта  типа  ObjName1'); End;

Procedure  ObjNamel.Met2;

Begin Fl1   :=   12;

Writeln ('Работает метод ObjName1.Met2: Fl1= ', Fl1) End;

{        Методы объекта  ObjName2      }

Procedure  ObjName2.Met2;

Begin Fl1   :=   34;

Writeln ('Работает метод ObjName2.Met2: Fl1 = ', Fl1) End;

Destructor ObjName2.Done; Begin

Writeln   ('Освобождается  ОП  объекта   типа  ObjName2'); End;

Var  V1 : PobjName1;   { - динамический объект V1 }

V2 : PObjName2;   { -    "        "     V2 }

{   Основная программа  }

Begin ClrScr;

Assign (Output, 'Dvirt.res'); Rewrite (output);

Writeln ('ДИНАМИЧЕСКИЕ ОБЪЕКТЫ, ВИРТУАЛЬНЫЕ МЕТОДЫ' ); Writeln ('Работаем с V1 - экземпляром типа предка');

{Вызывается конструктор Met1 для экземпляра V1 - предка:}

New (V1,Met1); {- создание динамического объекта V1 }
V1^.Met2; { - вызов метода ObjName1.Met2; }

{ Удаление объекта - только с помощью Dispose и Done: } Dispose (V1,Done); {- удаление объекта V1 деструктором

ObjName1.Done }

Writeln ('Работаем с V2- экземпляром типа потомка');

{Вызывается конструктор Met1 для экземпляра V2 - потомка V1:}
New ( V2, Met1 ); { - создание динамического объекта V2 }
V2^.Met2; { - вызов метода ObjName2 .Met2; }

{ Удаление объекта - только с помощью Dispose и Done: } Dispose (V2,Done);  { - удаление объекта V2 деструктором

ObjName2.Done}

Close (Output);

End.

Общие правила использования конструкторов и деструкторов: Constructor - для виртуальных методов, для создания ТВМ при использовании статических и динамических объектов.

Destructor - для освобождения ОП динамических объектов, содержащих виртуальные методы.

Контрольные вопросы

  1.  Что такое объектно-ориентированное программирование? Каковы его особенности и область применения?
  2.  Назовите свойства объектов.
  3.  Что такое инкапсуляция? Как объявить объект?
  4.  Что такое наследование и переопределение, предок, потомок? Как объявить объект-потомок?
  5.  Что такое полиморфизм? Как переопределить статический, виртуальный методы?
  6.  Как создать, удалить динамический объект?
  7.  Что такое конструктор, деструктор? Когда надо их использовать?


 

А также другие работы, которые могут Вас заинтересовать

4850. Раз добром налите серце – ввік не прохолоне. Виховний захід 251 KB
  Раз добром налите серце – ввік не прохолоне Мета: ознайомити учнів із жанром літературної чарівної казки формувати вміння визначати головну думку твору вчити дітей жити, діяти від щирого серця, творити добро і дарувати душевне тепло рідним, б...
4851. Засідання педагогічної ради з використанням проектної технології 94 KB
  Засідання педагогічної ради з використанням проектної технології Готовність педагогічного колективу до інноваційної діяльності як складова професійної компетентності Епіграф: Не досить оволодіти премудрістю, потрібно також уміти користуватися нею...
4852. Развитие малого предпринимательства в России 324.5 KB
  Развитие малого предпринимательства в России Введение Экономика любой страны не может нормально развиваться без оптимального сочетания крупного, среднего и малого бизнеса. Это доказывает мировая практика. Неотъемлемой частью рыночных отношений являе...
4853. Разработка бизнес-плана предприятия общественного питания ООО Гурман в г. Когалыме 509.5 KB
  Отечественные предприятия имеют относительно небольшой опыт работы в условиях рынка, да и рыночные отношения, еще далеки от их уровня в развитых странах. На многих предприятиях до настоящего времени современные подходы к планированию деятел...
4854. Мотивации трудовой деятельности персонала: теория и практика 406 KB
  Мотивации трудовой деятельности персонала: теория и практика В работе исследованы теоретические основы, в сущности, мотивация трудовой деятельности, мотивация персонала как системы, методы стимулирования персонала. Практический аспект мотивации труд...
4855. Технологии и методы программирования. Конспект лекций 297 KB
  Введение В курсе программирование рассматривается, как методология формализации записи решения задач на языке непосредственно не определяемым исполнителем, но понимаемым им до степени реализации. Эта позиция шире, чем изучение собственно конкретных...
4856. Объектно-ориентированное программирование на языке С++ 343.5 KB
  Объектно-ориентированное программирование на языке С++. Объектно-ориентированное программирование как методология проектирования программных средств. Что такое объектно-ориентированное программирование? Объектно-ориентированное программирование...
4857. Программирование на языке ассемблера 337.5 KB
  Введение Язык ассемблера — это символическое представление машинного языка. Все процессы в персональном компьютере (ПК) на самом низком, аппаратном уровне приводятся в действие только командами (инструкциями) машинного языка. По-настоящему реши...
4858. Основы микропрограммирования на языке Ассемблера. Лабораторные работы 322.5 KB
  Создание первой программы на языке Ассемблера Программирование арифметических операций Работа со строками Написание собственного обработчика прерывания Связь подпрограмм на Ассемблере с программами на языке высокого уровня Лабораторная работа №1 Со...