Зачем нам ооп и что это такое. Особенности объектно-ориентированного программирования

  • 21.07.2019
От переводчика: К сожалению, у меня нет сколько-нибудь значительного опыта перевода с английского, хотя я и довольно много читаю на английском. Но выяснилось, что читать и переводить – разные вещи. Также, к сожалению, у меня нет значительного опыта в программировании (недавно только сделал простейшее веб-приложение на Spring MVC и Hibernate). Поэтому перевод получился значительно хуже, чем мог бы быть. Я взял на себя смелость несколько подкорректировать примеры кода, которые даются в статье, так как они не соответствуют соглашениям по наименованию (code conventions) в Java. Возможно, не стоило переводить название некоторых паттернов (такой перевод мало что дает для понимания), но я посчитал, что это меньшее зло. Отдельно стоит сказать о "высокой сцепленности" как переводе "high cohesion". Согласен, не самый лучший перевод. Но "сильная связность" - это "high coupling" (другое важное понятие), а "когерентность" здесь вряд ли подойдет. Я открыт для критики и с признательностью приму замечания по статье в любой форме. Объектно-ориентированное программирование – это стиль программирования, в котором программа состоит из компонентов, соответствующих объектам реального мира Любой реальный объект имеет какие-то свойства (которые могут изменяться или нет с течением времени) и поведение (которое может меняться или нет в зависимости от других условий). Например, карандаш – это объект реального мира, который имеет следующие свойства:
  • Он красный (это не меняется с течением времени).
  • Он 10 сантиметров в длину сейчас (это может меняться, если карандаш заточить).
И он имеет следующее поведение:
  • Он оставляет след, если его использовать правильно.
  • След может отличаться в зависимости от давления (зависит от внешних факторов).
  • Его длина сокращается, если его затачивать (постоянное поведение).
Как в этом примере, объекты реального мира могут иметь много свойств, но при написании программ мы принимаем во внимание только необходимые свойства. Объектно-ориентированное программирование имеет свои преимущества. Например, оно облегчает установление связи между объектом реального мира и программой так, как это ожидается. Это реально помогает по мере того, как приложение растет и множество объектов взаимодействуют друг с другом. Это помогает в распределении ответственности внутри объективного мира, позволяя сфокусироваться на продумывании приложения. Другая важная особенность, ассоциируемая с (Объектно-ориентированным программированием), - это классификация объектов. Так как мир (реальный/виртуальный) полон объектов, сложно управлять по отдельности. Нам нужен способ классификации этих объектов, который поможет нам связать различные объекты и их свойства, например, черный карандаш. Он был бы неотличим (тот же самый?), если бы использовался в предыдущем примере, но это другой объект. Но так как это оба карандаши, они принадлежат одному и тому же классу «Карандаш». Тогда как ручка, которая очень похожа на карандаш, принадлежит к другому классу. Тем не менее, ручка и карандаш оба являются «Пишущими инструментами». Объектно-ориентированное программирование имеет следующие принципы:
Абстракция
Абстракция определяется как характерная черта (quality) взаимодействия с идеями, а не событиями или, другими словами, свобода от репрезентирующих качеств . Это позволяет программистам сфокусироваться на том, что программировать, а не как . Абстракцию можно рассматривать в качестве соглашения, посредством которого мы предоставляем функциональность. Детали реализации могут быть скрыты, если использовать этот концепт. Например, если нам нужен класс, который пишет, то мы должны быть уверены, что обладает методов «писать» abstract class writer { write (); } Что мы сделали? Мы разработали класс высокого уровня, являющийся абстрактными, иными словами, он знает, что за функциональность нам нужна, но как ее реализовать – это за пределами видимости (out of scope) данного класса. Это дает много преимуществ:
  • Мы раскрываем минимум информации необходимой внешним сущностям, это позволяет сосредоточиться на продумывании программы (this enable focused thinking), избежать путаницы и не давать непреднамеренных обещаний.
  • Мы оставляем место для улучшений в будущем, которые были бы невозможны, если детали реализации были раскрыты.
Наследование
«Наследование» в общеупотребительном английском означает «приобретать и передавать дальше». Это слова существует в нашей культуре очень давно. Предки приобретали землю с помощью тяжелой работы и передавали ее своим детям, даже природа благоволит наследованию. Все свойства тела, например, рост, цвет кожи/глаз/волос и т.д. зависят от генов, наследуем нами от наших родителей. Наследование предотвращает изобретение колеса заново и ускоряет прогресс. То же самое и в ООП. Мы создаем родительский класс с несколькими базовыми свойствами/поведением. Все классы, наследуемые от этого родителя, будут содержать такие же свойства/поведение, что и их родитель. Тем не менее, наследуемые классы могут получить больше свойств/поведения или изменить реализацию поведения. class WritingInstrument { colour; write() { } } class Pen (child of parent) { inkcolour; } В примере сверху класс-родитель (WritingInstrument) имеет свойство «цвет» и поведение «писать». Когда класс-наследник (ручка) объявляется, повторное объявление свойства «цвет» и поведения «писать» не требуется. Они присутствуют в классе «ручка» в силу наследования. Однако класс-наследник может объявить собственные дополнительные свойства/поведение. Как мы можем использовать это на практике? Мы, разработчики, очень ленивы. Мы не хотим печатать что-то снова и снова. Существование множества копий одного и того же кода не приветствуется в силу следующих соображений:
  • Чем меньше копий кода, тем легче его сопровождать.
  • Если нет множества копий кода, то изменение в одном месте становится видимым везде.
  • Чем меньше кода – тем меньше ошибок.
  • Если один код используется во многих местах, то так достигается обобщение.
  • Мы фокусируемся на написании кода.
  • Мы фокусируемся на тестах.
Наследование в Java достигается с помощью ключевых слов «extends» и «implements». class WritingInstrument { } class Pen extends WritingInstrument { }
Полиморфизм
Слова «полиморфизм» произошло от двух слов: «Поли» , т.е. «множество» / «больше, чем один» «морф» , т.е. «форма» Буквально, слово «полиморфизм» отсылает к способности объектов вести себя различным образом в зависимости от условий. В программировании полиморфизм может быть воплощен в нескольких местах:
  • Классы
  • Методы
  • Операторы
Все, перечисленное выше, может вести себя различным образом в зависимости от условий, возможно, от контекста, в которых они используются. Это полезно, так как клиенту (программисту, использующему ваши библиотеки) не нужно знать множество тонкостей, и желаемая функциональность реализуется посредством отбора необходимой информации из контекста. Class WritingObject { wrire() { // пишем, используя стандартные (по дефолту) цвета } } class Pencil extends WritingObject { write() { // пишем, используя серый цвет, написанный текст можно стереть } } class Pen extends WritingObject { write() { // пишем, используя голубой цвет, написанный текст нельзя стереть } } class Main { main() { WritingObject wr = new WritingObject(); wr.write(); // первый вызов WritingObject wr = new Pen(); wr.write(); // второй вызов WritingObject wr2 = new Pencil(); wr2.write(); // третий вызов } } В примере выше имеет реализация по умолчанию в WritingObject, которая расширена/переопределена классами-наследниками перо и ручка. Метод write() вызван три раза в классе Main. Каждый раз вызывается различная реализация в зависимости от того, у какого объекта вызывается этот метод. В данном случае метод write() имеет множество типов поведения, так как он полиморфичен.
Инкапсуляция
Инкапсуляция определяется как сбор связанных данный/функциональностей в одном модуле (unit). Это помогает в облегчении доступа/модификации данных. Например, если нам нужно напечатать все свойства, которыми данный пользователь обладает, мы имеем следующие опции: printUserProperties(userName, userId, firstname, lastname, email, phone, … … ….) Мы создали метод, который принимает все свойства и печатает их друг за другом. С увеличением количества элементов в списке пропадет возможность идентифицировать корректные поля, а добавление/удаление одного поля изменит сигнатуру метода. Поэтому нам нужно заменить всех пользователей этого метода, если даже недавно добавленные поля им не нужны. Чтобы сделать код более читаемым и упростить будущие модификации проще, мы инкапсулируем свойства в классе и превращаем его в коллективный объект (collective object) class User { userName userId firstname lastname email phone .. .. .. } printUserProperties(user) {} Объект – это система (software bundle) переменных и связанных методов. Вы можете представить объекты реального мира, используя объекты программы. Вы можете представить реальных собак в анимационной программе или реальный велосипед как программный объект внутри велотренажера. В ООП класс – расширяемый шаблон (program-code-template) для создания объектов, обеспечения их начальным состоянием (переменные) и реализацией поведения (функции, методы). Аббревиатура SOLID была введена Michael Feather’ом для «первых пяти принципов», названных так Robert C. Martin’ом в начале 2000-х. Целью принципов, реализуемых совместно, является увеличение вероятности того, что программист создаст систему, которую легко будет поддерживать и расширять. – ориентиры в разработке программ, которые необходимы для удаления «протухшего» кода посредством рефакторинга, в результате которого код должен стать легко читаемым и расширяемым. Это часть стратегии agile and adaptive programming (гибкого и адаптирующегося программирования).
Принцип единой ответственности (Single Responsibility Principle)
В ООП принцип единой ответственности гласит, что каждый класс должен быть ответственен за одну часть функциональности, обеспечиваемой программой, и что ответственность должна быть полностью инкапсулирована этим классом. Вся его функциональность должна быть тесно связана с этой ответственностью.
Принцип открытости/закрытости (Open/Closed Principle)
В ООП принцип открытости/закрытости гласит «сущности программного обеспечения (классы, модули, методы и т.д.) должны быть открыты для расширения, но закрыты для изменения». Иными словами, сущность должна позволять расширять ее поведение без изменения исходного кода.
Принцип подстановки Лисковой (Liskov Substitution Principle)
Возможность подстановки (Substituability) – это принцип в ООП. Он гласит, что если S в компьютерной программе является подтипом T, то объекты типа T должны быть такими, чтобы их можно было заменить объектами типа S (т.е. объекта типа S могут заменить объекты типа T) без изменения каких-либо требуемых свойств программы (точность, выполнение задачи и т.д.).
Принцип разделения интерфейса (Interface Segregation Principle)
Принцип разделения интерфейса гласит, что программист-клиент не должен быть принужден зависеть от методов, которые он не использует. Согласно этому принципу нужно разделять большие интерфейсы на маленькие и более специфичные, чтобы программист-клиент знал только о методах, которые ему интересны. Целью принципа разделения интерфейса является сохранение системы в несвязанном состоянии (system decoupled), что облегчит рефакторинг, внесение изменений и повторное развертывание (redeploy).
Принцип инверсии зависимостей (Dependency Inversion Principle)
В ООП принцип инверсии зависимости означает специфическую форму несвязности программных модулей. При следовании этому принципу стандартные отношения зависимости, установленные от модулей высокого уровня, формирующих архитектуру приложения (policy-setting) к зависимым модулям низкого уровня инвертированы (обращены), поэтому измененные модули высокого уровня становятся независимы от деталей реализации модулей низкого уровня. Этот принцип утверждает:
  • Модули высокого уровня не должны зависеть от модулей низкого уровня. Модули обоих типов должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей реализации. Детали должны зависеть от абстракций.
Принцип обращает (inverts) путь, согласно которому люди могут думать об объектно-ориентированном дизайне, утверждая, что объекты высокого и низкого уровней должны зависеть от одних и тех же абстракций.

Принципы GRASP

Паттерны (принципы), используемые для решения общих задач по назначению обязанностей классам и объектам (General Responsibility Assignment Software Patterns (GRASP)) содержат руководства (guidelines) по назначению ответственности классам и объектам в объектно-ориентированном дизайне.
Контроллер (Controller)
Паттерн Контроллер назначает ответственность за взаимодействие с системными событиями классов без графического интерфейса, которые представляют всю систему или use case scenario (сценарии вариантов использования). Контроллер:
  • Это не взаимодействующий напрямую с пользователем объект, ответственный за получение и реакцию на системные события.
  • Должен использоваться так, чтобы иметь дело со всем системными событиями одного (или множества взаимосвязанных) use cases.
  • Это первый объект за графическим интерфейсом, который контролирует системные операции.
  • Он не должен делать работу сам, его задача – контроль над потоком событий.
Создатель (Creator)
Задача класса-создателя – создание и инициация объектов для последующего использования. Он знает, параметры инициализации, а также какой объект будет создан. Иногда класс-создатель создает объекты активно и помещает их в кэш, и обеспечивает один экземпляр, когда он нужен.
Высокая сцепленность (High Cohesion)
Высокая сцепленность – оценочный паттерн, целью применения которого является сохранение объектов в таком состоянии, чтобы они были нацелены на выполнение одной четкой задачи, легко управляемы и понимаемы. Высокая сцепленность обычно используется для поддержки слабой связности (Low Coupling). Высокая связность означает, что ответственность данного элемента четко обозначена (strongly related and highly focused). Разбиение программы на классы и подсистемы – пример действий, что повышает сцепленность свойств системы. Слабая сцепленность, наоборот, - ситуация, в которой элемент имеет слишком много несвязанных задач. Элементы со слабой сцепленностью обычно отличаются тем, что их сложно понять, сложно повторно использовать, поддерживать и изменять.
Окольный путь (Indirection)
Паттерн Окольный путь поддерживает слабую связность (и возможность повторного использования) между двумя элементами, назначая ответственность за взаимодействие между ними промежуточному объекту. Примером является введение контроллера для посредничества между данными (моделью) и их отображением (представлением) в паттерне Модель-Представление-Контроллер (MVC).
Информационный эксперт (Information Expert)
Информационный эксперт (также Эксперт или принцип Эксперта) – принцип, используемый для определения того, кому делегировать ответственность. Ответственность включает методы, вычисляемые поля и т.д. При использовании данного принципа при назначении ответственности главным подходом является следующая последовательность действий: анализ ответственности, определение информации, которая нужна для ее исполнения, наконец, установление того, где эта информация находится. Использование принципа Информационный эксперт приводит к назначению ответственности классу, который имеет наибольшее количество информации для ее исполнения.
Слабая связность (Low Coupling)
Слабая связность – оценочный паттерн, который указывает, как назначать ответственность: слабая зависимость между классами, изменение одного должно иметь минимальные последствия для другого, максимальная возможность повторного использования.
Полиморфизм (Polymorphism)
В соответствии с полиморфизмом изменения поведения основывается на типе объекта, на который ссылается переменная (responsibility of defining the variation of behaviors based on type is assigned to the types for which this variation happens). Это достигается использованием полиморфных операций.
Защищенные изменения (Protected Variations)
Паттерн Защищенные изменения защищает элементы от изменений других элементов (объектов, систем, подсистем) путем обертывания центра нестабильности (the focus of instability) интерфейсом и использования полиморфизма для создания различных реализаций данного интерфейса.
Чистое конструирование (Pure Fabrication)
Чистое конструирование предполагает класс, не представляющий концепт в проблемной области (the problem domain) и созданный специально для достижения слабой связности, высокой сцепленности и, следовательно, максимального потенциала повторного использования (решение, предлагаемое паттерном Информационный эксперт этого не обеспечивает). Такая класс обычно называется “Service” в Предметно-ориентированном дизайне (Domain-driven design).

Критика

Исследования Potok’a и др. показали отсутствие существенных различий между ООП и процедурными подходами.
Критическое сравнение ООП с другими технологиями, в особенности реляционными, затруднено в силу отсутствия определения ООП, которое было бы строгим и широко принятым (Christopher J. Date)
В сравнении с другими языками (LISP диалекты, функциональные языка и т.д.) ООП языки не имеют уникального преимущества и навязывают ненужную сложность. (Lawrence Krubner)
Я нахожу объектно-ориентированное программирование технически неосновательным. Оно пытается разложить мир на части в терминах интерфейсов, которые изменяются в пределах одного типа. Чтобы иметь дело с реальными проблемами, вам нужны многосортные алгебры - семейства интерфейсов, которые простираются на многие типы. Я нахожу объектно-ориентированное программирование философски нездоровым. Оно утверждает, что всё является объектом. Даже если это так, это не очень интересно: сказать, что всё является объектом -- значит, не сказать вообще ничего. (Александр Степанов)
Популярность ООП среди больших компаний связана с «большими (и часто меняющимися) группами посредственных программистов». Дисциплина, навязываемая ООП, предотвращает нанесение программистом «слишком большого вреда». (Paul Graham)
Объектно-ориентированное программирование ставит существительные первыми и самыми главными. Зачем идти на такие крайние меры и ставить одну часть речи на пьедестал? Почему один концепт получает преимущество над другим? Это невозможно, чтобы ООП внезапно сделало глаголы менее важными для нашего мышления. Это странным образом перекошенная перспектива. (Steve Yegge)
Rick Hickey, создатель Clojure, описывал объектные системы как крайне упрощенные модели реального мира. Он подчеркивал неспособность ООП моделирования времени правильно, что создает огромные проблемы, когда в программах большое распространение получает многопоточность. Eric S. Raymond, Unix-программист и сторонник программного обеспечения с открытым кодом, был критически настроен в отношении заявления, что ООП является «Единственно верным решением», и писал, что ООП поощряет многослойные программы, что препятствует понятности (transparency). В качестве противоположного подхода Raymond приводил пример Unix и С.

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

Что такое ООП

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

  • инкапсуляция;
  • наследование;
  • полиморфизм.

Некоторые принципы, которые были изначально заложены в первые ООЯ, подверглись существенному изменению.

Примеры объектно-ориентированных языков:

  1. Pascal. С выходом Delphi 7 на официальном уровне стал называться Delphi. Основная область использования Object Pascal - написание прикладного ПО.
  2. C++ широко используется для разработки программного обеспечения, является одним из самых популярных языков. Применяется для создания ОС, прикладных программ, драйверов устройств, приложений, серверов, игр.
  3. Java - транслируется в байт-код, обрабатывается виртуальной машиной Java. Преимуществом такого способа выполнения является независимость от операционной системой и оборудования. Существующие семейства: Standard Edition, Enterprise Edition, Micro Edition, Card.
  4. JavaScript применяется в качестве языка сценариев для web-страниц. Синтаксис во многом напоминает Си и Java. Является реализацией Ecmascript. Сам Ecmascript используется в качестве основы для построения других таких как JScript, ActionScript.
  5. Objective-C построен на основе языка Си, а сам код Си понятен компилятору Objective-C.
  6. Perl - высокоуровневый интерпретируемый динамический язык общего назначения. Имеет богатые возможности для работы с текстом, изначально разработан именно для манипуляций с текстом. Сейчас используется в системном администрировании, разработке, сетевом программировании, биоинформатике и т. д.
  7. PHP. Аббревиатура переводится как препроцессор гипертекста. Применяется для разработки веб-приложений, в частности серверной части. С его помощью можно создавать gui-приложения с помощью пакетов WinBinder.
  8. Python - язык общего назначения, ориентирован на повышение производительности разработчика и читаемость кода. Был разработан проект Cython, с помощью которого осуществляется трансляция программ, написанных на Python в код на языке Си.

Абстракция

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

Абстрактный тип данных представляется как интерфейс или структура. Позволяет не задумываться над уровнем детализации реализации. АТД не зависит от других участков кода.

Известный афоризм Дэвида Уилера гласит: Все проблемы в информатике можно решить на другом уровне абстракции.

Наследование

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

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

Существует несколько типов наследования:

  • простое;
  • множественное.

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

Наследование выглядит так:

function draw() {

return "just animal";

function eat() {

return "the animal is eating";

class Cow extends Animal {

function draw() {

Return "something that looks like a cow";

Видим, что class Cow унаследовал все методы от class Animal. Теперь, если выполнить Cow.eat(), получаем "the animal is eating", соответственно, метод draw() изменен. Cow.draw() вернет “something that looks like a cow”, а Animal.draw() вернет “just animal”.

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

Инкапсуляция ограничивает доступ компонентов к другим, связывает данные с методами для обработки. Для инкапсуляции используется спецификатор доступа private.

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

function __construct($name) {

$this->name = $name;

function getName() {

return $this->name;

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

Полиморфизм

Полиморфизм позволяет использовать одно и то же имя для решения схожих, но технически разных задач.

В примере выше находится таблица. Мы видим class CardDesk и class GraphicalObject. У обоих есть функция под названием draw(). Она выполняет разные действия, хотя имеет одно имя.

Ad hoc полиморфизм или специальный полиморфизм использует:

  • перегрузку функций, методов;
  • приведение типов.

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

Приведение типов означает преобразование значения одного типа в значение другого типа. Существует явное преобразование - применяется функция, которая принимает один тип, а возвращает другой, неявное - выполняется компилятором или интерпретатором.

«Один интерфейс — много реализаций» Бьерн Страуструп.

Класс

Класс - это такой тип данных, который состоит из единого набора полей и методов.

Имеет внутренние и внешние интерфейсы для управления содержимым. При копировании через присваивание копируется интерфейс, но не данные. Разные виды взаимодействуют между собой посредством:

  • наследования;
  • ассоциации;
  • агрегации.

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

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

В Object Pascal описывается следующим образом:

ClassName = class(SuperClass)

{ использование элементов ограничивается только пределами модуля }

{ здесь указываются поля }

{ спецификатор доступа стал доступным с выходом Delphi 2007, обозначает то же, что и private }

{ элементы могут использоваться внутри ClassName или при наследовании }

{ элементы доступны всем, они отображаются в Object Inspector"e }

Здесь SuperClass - предок, от которого происходит наследование.

Для C++ создание выглядит так:

class MyClass: public Parent

MyClass(); // конструктор

~MyClass(); // деструктор

В этом примере Parent является предком, если таковой имеется. Спецификаторы private, public, protected обозначают то же самое, что в предыдущем примере на Паскале. Также мы видим конструктор, деструктор, доступные для любой части программы. У C++ все элементы по умолчанию являются private, соответственно, это можно не указывать.

Особенности реализации

В центре объектно-ориентированных языков - объект, он является частью класса. Он состоит из:

  • поля;
  • метода.

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

Метод - совокупность функций, которые определяют все возможные действия, доступные для выполнения над объектом. Все объекты взаимодействуют за счет вызова методов друг друга. Могут быть внешними или внутренними, что конкретизируется модификаторами доступа.

ООП-методологии

Существуют такие методологии:

  • Компонентно-ориентированное программирование;
  • Прототипное программирование;
  • Классоориентированное программирование.

Компонентно-ориентированное программирование опирается на понятие компонента - такого составляющего программы, которое предназначено для повторного использования. Реализуется как множество конструкций с общим признаком, правилами, ограничениями. Подход используется в объектно-ориентированном языке Java, где компонентная ориентация реализуется посредством “JavaBeans”, написанных по одним правилам.

В прототипном программировании нет понятия класса - наследование производится за счет клонирования существующего прототипа. Это основа объектно-ориентированных языков javascript и других диалектов ecmascript, а также lua или lo. Главные особенности:

  • потомки не должны сохранять структурное подобие прототипа (в отношении класс - экземпляр это происходит именно так);
  • при копировании прототипа все методы наследуются один в один.

Классоориентированное программирование фокусируется на и экземпляр. Класс определяет общую структуру, поведение для экземпляров, которые их перенимают.

Объектно-ориентированные языки

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

ООЯ обязательно содержит набор следующих элементов:

  • объявление классов с полями, методами;
  • расширение за счет наследования функций;
  • полиморфное поведение.

Кроме вышеперечисленного списка, могут быть добавлены дополнительные средства:

  • конструктор, деструктор, финализаторы;
  • свойства;
  • индексаторы;
  • модификаторы доступа.

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

ЯП поддерживают больше, чем одну парадигму. Например, PHP или JavaScript поддерживают функциональное, процедурное, объектно-ориентированное программирование. Java работает с пятью парадигмами: объектно-ориентированной, обобщенной, процедурной, аспектно-ориентированной, конкурентной. C# считается одним из самых успешных примеров мультипарадигмальности. Он поддерживает те же подходы, что Java, к этому списку добавляется еще рефлексивная парадигма. Такой ЯП, как Oz, разработан для того, чтобы объединить все понятия, традиционно связанные с различными программными парадигмами.

(как расшифровывается ООП) – это, прежде всего, парадигма программирования.
Парадигма программирования определяет то, как программист видит выполнение программы.
Так, для парадигмы ООП характерно, что программист рассматривает программу в виде набора взаимодействующих объектов, в то время как, например, в функциональном программировании программа представляется в виде последовательности вычисления функций. Процедурное программирование или, как его еще правильно называют, классическое операциональное, подразумевает написание алгоритма для решения задачи; при этом ожидаемые свойства конечного результата не описываются и не указываются. Структурное программирование в основном придерживается тех же принципов, что и процедурное, лишь немного дополняя их полезными приемами.
Парадигмы непроцедурного программирования, к которым можно отнести объектно-ориентированную парадигму, имеют совершенно другие идеи.
Определение Гради Буча гласит: “Объектно-ориентированное программирование – это методология программирования, которая основана на представлении программы в виде совокупности объектов, каждый из которых является реализацией определенного класса (типа особого вида), а классы образуют иерархию на принципах наследуемости”.
Структурное и объектно-ориентированное программирование строятся на таком научном методе как декомпозиция — метод, который использует структуру задачи и позволяет разбить решение общей большой задачи на решение последовательности меньших задач. Декомпозиция ООП происходит не по алгоритмам, а по объектам, использующимся при решении задачи. Данная декомпозиция уменьшает размер программных систем благодаря повторному использованию общих механизмов. Известно, что системы визуального программирования или системы, построенные на принципах объектно-ориентированного программирования, являются более гибкими и легче эволюционируют со временем.

История развития ООП берет свое начало в конце 60-х годов. Первым объектно-ориентированным языком был язык программирования Simula, созданный в компьютерном центре в Норвегии. Язык предназначался для моделирования ситуаций реального мира. Особенностью Simula было то, что программа, написанная на языке, была организована по объектам программирования. Объекты имели инструкции, называемые методами, и данные, которые назывались переменными; методы и данные определяли поведение объекта. В процессе моделирования объект вел себя согласно своему стандартному поведению и, в случае необходимости, изменял данные для отражения влияния назначенного ему действия.

Сегодня существует достаточное количество объектно-ориентированных языков программирования , наиболее популярными из которых в настоящее время являются C++, Delphi, Java, Visual Basic, Flash. Но, кроме того, многие языки, которые принято причислять к процедурной парадигме, тоже обладают свойствами ООП, имея возможность работать с объектами. Так, объектно-ориентированное программирование в C — это большой раздел программирования на данном языке, то же самое касается ООП в python и многих других структурных языках.

Говоря об ООП, часто всплывает еще одно определение — визуальное программирование . Оно дополнительно предоставляет широкие возможности использования прототипов объектов, которые определяются как классы объектов.
События. Во многих средах визуального программирования реализована характеристика (помимо инкапсуляции, полиморфизма и наследования) объекта – событие. Событиями в объектно-ориентированном программировании называется возможность обработки так называемых сообщений (или событий), получаемых от операционной системы Windows или самой программы. Данный принцип характерен для всех компонентов среды, которые обрабатывают различные события, возникающие в процессе выполнения программы. По сути, событие — это некоторое действие, которое активизирует стандартную реакцию объекта. Событием может рассматриваться, например, щелчок по кнопке мыши, наведение курсора мыши на пункт меню, открытие вкладки и т.п. Очередность выполнения тех или иных действий определяется как раз таки событиями, возникающими в системе, и реакцией на них объектов.
Классы и объекты в ООП — различные понятия. Понятие класса в ООП – это тип данных (такой же как, например, Real или String), а объект – конкретный экземпляр класса (его копия), хранящийся в памяти компьютера как переменная соответствующего типа.
Класс является структурным типом данных. Класс включает описание полей данных, а также процедур и функций, которые работают с этими полями данных. Метод ООП – это и есть такие процедуры и функции применительно к классам.
Классы имеют поля (как тип данных запись — record), свойства, которые похожи на поля, но имеют дополнительные описатели, определяющие механизмы записи и считывания данных и методы — подпрограммы, которые направленны на изменение полей и свойств класса.

Основные принципы ООП

Принципы объектно-ориентированного программирования помимо обработки событий – это инкапсуляция, наследование, подклассы и полиморфизм. Они особенно полезны и необходимы при разработке тиражируемых и простых в сопровождении приложений.
Объект объединяет в себе методы и свойства, которые не могут существовать отдельно от него. Поэтому если объект удаляется, то удаляются его свойства и связанные с ним методы. При копировании происходит то же самое: объект копируется как единое целое. Инкапсуляция ООП — это и есть описанная характеристика.

Принцип наследования ООП и подклассы

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

Полиморфизм ООП

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

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

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

Первый ряд примеров событий доставляет собственно сам жизненный цикл объекта:

  • создание объекта;
  • уничтожение объекта.

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

Современными языками объектно-ориентированного программирования являются С++ и Java . С середины 90-х годов многие объектно–ориентированные языки реализуются как системы визуального программирования , в которых интерфейсная часть программного продукта создается в диалоговом режиме, практически без написания программных операторов. К объектно – ориентированным системам визуального проектирования относятся Visual Basic , Delphi , C++ Builder , Visual C++. Язык VBA (Visual Basic for Applications) – язык приложений Microsoft Office (Excel , Word , Access , Power Point и др). VBA соблюдает основной синтаксис языка и правила программирования языков Basic – диалектов, позволяет создавать макросы для автоматизации выполнения некоторых операций и графический интерфейс пользователя, интеграцию между различными программными продуктами.

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

Лабораторные работы

  1. Объектно-ориентированное программирование для начинающих
  2. Лабораторная работа 1 по Adobe Flash: Рисование и закрашивание
  3. Лабораторная работа 2 по Adobe Flash: Символы и их трансформы
  4. Лабораторная работа 7 по Adobe Flash: Кадрированная анимация
  5. Лабораторная работа 9 по Adobe Flash: Вставка Flash-объекта в html-файл
  6. ООП в JavaScript. Лабораторная работа 1
    Основные понятия и определения: объект, метод, свойства, события
  7. ООП в JavaScript. Лабораторная работа 3. Форма, кнопка, текстовое поле
  8. ООП в JavaScript. Лабораторная работа 4. Типы данных. Переменные. Арифметические операции. Условная операция
  9. Введение в интерфейс, объекты и новые возможности MS Access 2007
  10. Лаб.2. Модификация базы данных. Использование связанных таблиц. Создание форм и отчетов

Литература

  1. Бруно Бабэ. Просто и ясно о Borland C++: Версии 4.0 и 4.5/ Пер. с англ. -М.:БИНОМ, 1994. - 400с.
  2. Буч Г. «Объектно-ориентированный анализ и проектирование с примерами приложений на С++» Пер. с англ. - М.: Бином; СПб.: Невский диалект, 1999.
  3. . - М, 2000
  4. Гайсарян С.С. «Объектно-ориентированное проектирование» (http://www.mista.ru/oop_book/index.htm)
  5. Жуков А. «Изучаем С» - СПб.: Питер, 2003.
  6. - Adobe Systems, 2010.
  7. Ишкова Э. «С++ начала программирования» - М.: Бином, 2001.
  8. Клочков Д.П., Павлов Д.А. Введение в объектно-ориентированное программирование. / Учебно-методическое пособие. - Изд. Нижегор. ун-та, 1995. - 70с.
  9. Легалов А. «Итоги экспансии объектно-ориентированной парадигмы» (http://www.softcraft.ru/paradigm/process/pr01.shtml
  10. Мухортов В.В., Рылов В.Ю. (методическое пособие) - ИМСО РАН, Новосибирск, 2002
  11. Немнюгин С., Перколаб Л. «Изучаем TurboPascal
  12. Плискин М. «Эволюция языков программирования» (://2..cctpu../edu///lang/_09.)
  13. . - МИФИ, 2003
  14. Объектно-ориентированная методология программирования (http://www.math.rsu.ru/smalltalk/sml-a.ru.html)
  15. Объектно-ориентированные системы: состояние и перспективы. Аналитический обзор по материалам фирмы OVUM. Обзор подготовил А.Г. Иванов. (http://www.math.rsu.ru/smalltalk/obzornew.ru.html)
  16. Объектно-ориентированные языки программирования. Сравнение с традиционными языками (://.suvvbcourse/1.)
  17. Патрикеев Ю.Н. «Объектно-ориентированное проектирование» (http://www.object.newmail.ru/oop1.html)
  18. Патрикеев Ю.Н. «Объектно-ориентированное программирование на Borland C++» (http://www.object.newmail.ru/obj0.html)
  19. Принципы объектно-ориентированного программирования – Лекции по системе визуального объектно-ориентированного проектирования Delphi - Лекции (http://blackman.wp-club.net/lection/visualprg.php)
  20. Стили программирования (http://media.karelia.ru/~ftt/IVK/new2/Inflect/T_1_16.htm)
  21. Страуструп Б. Язык программирования С++ (2-ред)./Пер. с англ.-М.: Радио и связь, 1995. - 352с.

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

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

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

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

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

К преимуществам ООП относятся:

  • ? использование при программировании понятий, более близких к предметной области;
  • ? более простая структура программы в результате инкапсуляции, т.е. объединения свойств и поведения объекта и скрытия деталей его реализации;
  • ? возможность повторного использования кода за счет наследования;
  • ? сравнительно простая возможность модификации программы;
  • ? возможность создания библиотек объектов.

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

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

Объекты В ПАСКАЛЕ объект - это тип данных,

Определяемый программистом. Объект

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

type имя = object

описание элементов

заголовки методов

Поля и методы называются элементами объекта. Их видимостью управляют директивы private и public 1 . Ключевое слово private (закрытые ) ограничивает видимость перечисленных после него элементов файлом, в котором описан объект. Действие директивы распространяется до другой директивы или до конца объекта. В объекте может быть произвольное количество разделов private и public. По умолчанию все элементы объекта считаются видимыми извне, т.е. являются public (открытыми).

Для каждого поля объекта задается его имя и тип. Он может быть любым, кроме типа того же объекта, но может быть указателем на этот тип.

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

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

Квадратные скобки означают, что эти директивы являются необязательными.

определенными «запасами» здоровья и вооружения и цветом, а также умеет атаковать противника: type monster = object

procedure init (x_, y_, health_, ammo_: word);

procedure attack;

procedure erase;

procedure move (x_, y_: word); private

health, ammo: word; color: word;

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

Описание методов (текст подпрограмм) размещается вне объекта в разделе описания процедур и функций:

procedure monster.init (х_, у_, health_, ammoj word); begin x:= x_; y:= y_; health:= health_; ammo:= ammo_; color:= yellow; end; procedure monster.draw; begin ... {процедуры вывода изображения} end;

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

private, а методы - public.

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

Экземпляры объектов Экземпляр объекта - это переменная

Объектного типа. Время жизни и видимость объектов зависят от вида и места их описания и подчиняются общим правилам ПАСКАЛЯ. Экземпляры объектов можно создавать в статической или динамической памяти:

var Vasia: monster; {описывается статический объект} pm: "?"monster; {описывается указатель на объект}

new (pm); {создается динамический объект}

Можно определять массивы объектов или указателей на объекты и создавать из них динамические структуры данных. Если объектный тип описан в модуле, для создания в программе переменных этого типа следует подключить модуль в разделе uses: uses graph, monsters;

Доступ к элементам объекта осуществляется либо с использованием составного имени, либо с помощью оператора with: Vasia.erase;

with pm A do begin init (100, 100, 30); draw; end;

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

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

Объекты одного типа можно присваивать друг другу, при этом выполняется поэлементное копирование всех полей. Кроме того, в ПАСКАЛЕ определены правила расширенной совместимости типов объектов. Они рассмотрены далее. Все остальные действия выполняются над отдельными полями объектов.

Управлять большим количеством Иерархии объектов

разрозненных объектов сложно. С этим -

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

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

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

Пусть требуется ввести в игру еще один тип персонажей, который должен обладать свойствами объекта monster, но по-другому выглядеть и атаковать:

type daemon = object (monster)

procedure init (x_, y_, health_, ammo_, magic_: word);

procedure attack; procedure draw; procedure erase; procedure wizardry; private

magic: word; end;

{---реализация методов объекта daemon---->

procedure daemon.init (x_, y_, health_, ammo_, magic_: word); begin

inherited init (x_, y_, health_, ammoj; color:= green; magic:= magic_; end;

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

Наследование методов. В «потомке» объекта можно не только описывать новые методы, но и переопределять существующие. Метод можно переопределить либо полностью, либо дополнив метод «предка».

Последний вариант иллюстрируется с помощью метода in it. В объекте daemon этот метод переопределен. Из него с помощью ключевого слова inherited (унаследованный) сначала вызывается старый метод, а затем выполняются дополнительные действия. Можно вызвать метод «предка» и явным образом с помощью конструкции monster, init.

Совместимость типов ПАСКАЛЬ - язык со строгой типизацией,

объектов Операнды выражений, параметры под-

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

  • 1) между экземплярами объектов;
  • 2) между указателями на экземпляры объектов;
  • 3) между параметрами и аргументами подпрограмм.

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

pmonster = A monster; pdaemon = ^daemon; var m: monster; d: daemon; pm: pmonster; pd: pdaemon;

Рис. 6.6.

Поля и методы, введенные в потомке, после таких присваиваний недоступны. Даже если метод переопределен в потомке, через указатель на предка вызывается метод, описанный в предке. Так, в результате выполнения оператора pm A .draw на экране появится изображение объекта-предка, потому что тип вызываемого метода соответствует типу указателя, а не типу того объекта, на который он ссылается.

Если известно, что указатель на предка на самом деле хранит ссылку на потомка, можно обратиться к элементам, определенным в потомке, с помощью явного преобразования типа, например pdaemon (pm) A .wizardry.

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

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

Рассмотрим работу компилятора при Виртуальные методы

использовании в программе иерархий -

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

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

procedure attack; virtual;

Объявление метода виртуальным означает, что все ссылки на этот метод будут разрешаться по факту его вызова, т.е. не на стадии компиляции, а во время выполнения программы. Для реализации этой возможности необходимо, чтобы адреса виртуальных методов хранились там, где ими можно в любой момент воспользоваться, поэтому компилятор формирует для них таблицу виртуальных методов (Virtual Method Table-VMT). Для каждого объектного типа создается одна VMT.

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

type monster = object

constructor init (x_, y_, health_, ammo_: word);

procedure attack; virtual;

procedure draw; virtual;

procedure erase; virtual;

procedure move (x_, y_: word);

x, у: word; health, ammo: word; color: word;

daemon = object (monster)

constructor init (x_, y_, health_, ammo_, magic_: word); procedure attack; virtual;

procedure draw; virtual; procedure erase; virtual; procedure wizardry; private

magic: word; end;

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

Конструктор обычно используется для инициализации объекта.

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

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

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

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

  • 1. Если в объекте метод определен как виртуальный, во всех потомках он также должен быть виртуальным.
  • 2. Заголовки всех одноименных виртуальных методов должны совпадать.
  • 3. Переопределять виртуальный метод в каждом из потомков не обязательно: если он выполняет устраивающие потомка действия, он будет унаследован.
  • 4. Объект, имеющий хотя бы один виртуальный метод, должен содержать конструктор.
  • 5. При описании объектов рекомендуется определять как виртуальные те методы, которые в его потомках будут реализовываться по-другому.

Рис. 6.7.

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

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

Для выделения памяти под объекты используются процедура и функция new. Например, если определены указатели:

pmonster = A monster; pdaemon = A daemon;

var pm: pmonster; pd: pdaemon;

можно создать объекты с помощью вызовов: new (pm); {или pm:= new (pmonster);} new (pd); {или pd:= new (pdaemon);}

Так как после выделения памяти объект обычно инициализируют, для удобства определены расширенные формы new со вторым параметром - конструктором объекта: new (pm, init (1, 1, 1, 1);

{или pm:= new (pmonster, init (1, 1, 1, 1));} new (pd, init (1, 1, 1, 1, 1);

{или pd:= new (pdaemon, init (1, 1, 1, 1, 1));} Обращение к методам динамического объекта выполняется по обычным правилам:

pm^.draw; pmA.attack;

С объектами в динамической памяти часто работают через указатели на базовый класс, т.е. описывают указатель базового класса, а инициализируют его, создав объект производного класса: pm: = new (pdaemon, init (1, 1, 1, 1, 1));

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

Деструкторы

Для освобождения памяти, занятой объектом, применяется процедура

Она освобождает количество байтов, равное размеру объекта, соответствующего типу указателя. Если в указателе хранится ссылка на объект производного класса, будет освобождено неверное количество байтов. Для корректного освобождения памяти из-под полиморфных объектов следует использовать вторым параметром Dispose специальный метод - деструктор. В документации по Borland Pascal ему рекомендуется давать имя done:

destructor monster.done; begin end; Dispose (pm, done);

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

Компилятор по служебному слову destructor вставляет в конец тела метода операторы получения размера объекта из VMT. Деструктор передает этот размер процедуре Dispose, и она освобождает количество памяти, соответствующее фактическому типу объекта. Деструкторы обязательно использовать только для динамических полиморфных объектов. В объекте можно определить несколько деструкторов (в этом случае они должны иметь разные имена).