Основные понятие объектно-ориентированного программирования
Содержание:
Введение
Исторически сложилось так, что программирование возникло и развивалось как процедурное программирование, которое предполагает, что основой программы является алгоритм, процедура обработки данных. Объектно-ориентированное программирование - это методика разработки программ, в основе которой лежит понятие объекта как некоторой структуры, описывающей объект реального мира, его поведение. Задача, решаемая с использованием методики объектно-ориентированного программирования, описывается в терминах объектов и операций над ними, а программа при таком подходе представляет собой набор объектов и связей между ними. Другими словами можно сказать, что объектно-ориентированное программирование представляет собой метод программирования, который весьма близко напоминает наше поведение. Оно является естественной эволюцией более ранних нововведений в разработке языков программирования. Объектно-ориентированное программирование является более структурным, чем все предыдущие разработки, касающиеся структурного программирования. Оно также является более модульным и более абстрактным, чем предыдущие попытки абстрагирования данных и переноса деталей программирования на внутренний уровень.
Использование объектно-ориентированного программирования является хорошим решением при разработке крупных программных проектов. Чем проект объемнее и сложнее, тем больше выгоды вы получите при использовании объектно-ориентированной технологии программирования. Одним из наибольших преимуществ объектно-ориентированного программирования является возможность многократного использования программного кода. Если вы, к примеру, создали класс, то можете порождать от него новые классы и изменять их свойства и функциональное назначение.
В качестве примера объектно-ориентированного языка в дальнейшем будем рассматривать Borland Pascal. Языковые расширения Borland Pascal предоставляют все средства объектно-ориентированного программирования: большую структурированность и модульность, большую абстрактность и встроенную непосредственно в язык возможность повторного использования. Все эти характеристики соответствуют коду, который является более структурированным, более гибким и более легким для обслуживания.
Объектно-ориентированное программирование требует оставить в стороне характерные представления о программировании, которые долгие годы рассматривались как стандартные. Однако после того, как это сделано, объектно-ориентированное программирование становится простым, наглядным и превосходным средством разрешения многих проблем, которые доставляют неприятности традиционному программному обеспечению.
1. Основные понятия объектно-ориентированного программирования
Объектно-ориентированное программирование – это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.
В основе объектно-ориентированного язык программирования лежат два основных понятия: объект и класс. Основными характеристическими свойствами этих понятий являются:
Инкапсуляция - комбинирование записей с процедурами и функциями, манипулирующими полями этих записей, формирует новый тип данных - объект (под записью понимается переменная типа "запись").
Наследование - определение объекта и его дальнейшее использование для построения иерархии порожденных объектов с возможностью для каждого порожденного объекта, относящегося к иерархии, доступа к коду и данным всех порождающих объектов.
Полиморфизм - присваивание действию одного имени, которое затем совместно используется вниз и вверх по иерархии объектов, причем каждый объект иерархии выполняет это действие способом, именно ему подходящим.
2. Объект - как базовое понятие в объектно-ориентированном программировании
Понятию “объект” сопоставляют ряд дополняющих друг друга определений. Ниже приведены некоторые из них.
Объект - это осязаемая реальность, характеризующаяся четко определяемым поведением.
Объект - особый опознаваемый предмет, блок или сущность (реальная или абстрактная), имеющая важное функциональное назначение в данной предметной области.
Объект может быть охарактеризован структурой, его состоянием, поведением и индивидуальностью. Состояние объекта определяется перечнем всех возможных (обычно статических) свойств и текущими значениями (обычно динамическими) каждого из этих свойств. Свойства объекта характеризуются значениями его параметров. Поведение объекта описывает, как объект воздействует на другие объекты или как он подвергается воздействию со стороны других объектов с точки зрения изменения его собственного состояния и состояния других объектов. Говорят также, что поведение объекта определяется его действиями. Определенное воздействие одного объекта на другой с целью вызвать соответствующую реакцию называют операцией. В объектно-ориентированных языках программирования операции называют методами.
Можно выделить пять типов операций:
- конструктор, создание и инициализация объекта;
- деструктор, разрушающий объект;
- модификатор, изменяющий состояние объекта;
- селектор для доступа к переменным объекта без их изменения;
- итератор для доступа к содержанию объекта по частям в определенной последовательности.
Известна и другая классификация методов объекта, когда выделяют функции управления, реализации, доступа и вспомогательные функции.
Под индивидуальностью объекта понимают свойство объекта, позволяющее отличать этот объект от всех других объектов.. В большинстве языков программирования при создании объект именуется, поэтому многие путают адресуемость и индивидуальность. Невозможность отличить имя объекта от самого объекта является источником множества ошибок в ООП.
Объекты могут находиться в определенных отношениях друг к другу. Эти отношения могут быть иерархическими. Основные иерархические отношения - это отношения использования и включения. Отношение использования реализуется посылкой сообщений от объекта A к объекту B. При этом объект A может выступать в роли:
- активного или воздействующего объекта, когда он воздействует на другие объекты, но сам воздействию не подвергается;
- пассивного или исполняющего, когда объект подвергается воздействию, но сам на другие объекты не воздействует;
- посредника, если объект и воздействует и сам подвергается воздействию.
Отношение включения имеет место, когда составной объект содержит другие объекты. Состояние объекта характеризуется перечнем (обычно статическим) всех свойств данного объекта и текущими (обычно динамическими) значениями каждого из этих свойств. Поведение объекта – это то, как объект действует и реагирует; поведение выражается в терминах состояния объекта и передачи сообщений. Операцией называется определенное воздействие одного объекта на другой с целью вызвать соответствующую реакцию. Например, клиент может активизировать операции append() и pop() для того, чтобы управлять объектомочередью: class Queue { public: Queue(); Queue(const Queue&); virtual ~Queue(); virtual Queue& operator=(const Queue&); virtual int operator==(const Queue&) const; int operator!=(const Queue&) const; virtual void clear(); virtual void append(const void*); virtual void remove(int at); virtual int length() const; virtual int isEmpty() const; ....
2.1 Инкапсуляция
Объекты моделируют характеристики и поведение элементов мира, в котором мы живем. Они являются окончательной абстракцией данных.
Объекты содержат вместе все свои характеристики и особенности поведения. Отношения частей к целому и взаимоотношения между частями становятся понятнее тогда, когда все содержится вместе в одной упаковке. Это и называется инкапсуляцией. Инкапсуляция – это процесс отделения друг от друга элементов объекта, определяющих его устройство и поведение. Инкапсуляция служит для того, чтобы изолировать контрактные обязательства абстракции от их реализации. Пусть члену класса требуется защита от «несанкционированного доступа». Как разумно ограничить множество функций, которым такой член будет доступен? Очевидный ответ для языков, поддерживающих объектно-ориентированное программирование, таков: доступ имеют все операции, которые определены для этого объекта, иными словами, все функции-члены. Например: class window { // ... protected: Rectangle inside; // ... }; class dumb_terminal: public window { // ... public: void prompt(); // ... }; Здесь в базовом классе window член inside типа Rectangle описывается как защищенный (protected), но функции-члены производных классов, например, dumb_terminal::prompt(), могут обратиться к нему и выяснить, с какого вида окном они работают. Для всех других функций член window::inside недоступен. В таком подходе сочетается высокая степень защищенности с гибкостью, необходимой для программ, которые создают классы и используют их. 10 Неочевидное следствие из этого: нельзя составить полный и окончательный список всех функций, которым будет доступен защищенный член, поскольку всегда можно добавить еще одну, определив ее как функцию-член в новом производном классе. Для метода абстракции данных такой подход часто бывает мало приемлемым. Если язык ориентируется на метод абстракции данных, то очевидное для него решение – это требование указывать в описании класса список всех функций, которым нужен доступ к члену. В С++ для этой цели используется описание частных (private) членов. Важность инкапсуляции, т.е. заключения членов в защитную оболочку, резко возрастает с ростом размеров программы и увеличивающимся разбросом областей приложения.
2.2 Наследование как важнейшее свойство объекта
Не менее важным является и тот факт, что объекты могут наследовать характеристики и поведение того, что мы называем порождающие, родительские объекты (или предки). Здесь происходит качественный скачок: наследование, возможно, является сегодня единственным самым крупным различием между обычным программированием на Паскале и объектно-ориентированным программированием в Borland Pascal.
В терминах Паскаля, объект во многом схож с записью, которая является оболочкой для объединения нескольких связанных элементов под одним именем.
Процесс, с помощью которого один тип наследует характеристики другого типа, называется наследованием. Наследник называется порожденным (дочерним) типом, а тип, которому наследует дочерний тип, называется порождающим (родительским) типом. Ранее известные типы записей Паскаля не могут наследовать. Однако Borland Pascal расширяет язык Паскаля для поддержки наследования. Одним из этих расширений является новая категория структуры данных, связанная с записями, но значительно более мощная. Типы данных в этой новой категории определяются с помощью нового зарезервированного слова object. Тип объекта может быть определен как полный, самостоятельный тип в манере описания записей Паскаля, но он может определяться и как потомок существующего типа объекта путем помещения порождающего (родительского) типа в скобки после зарезервированного слова object.
Большая часть конструирования объектно-ориентированных прикладных программ состоит в построении иерархии объектов, являющейся отражением генеалогического дерева объектов в приложениях.
Как показали данные определения, объекты тесно связаны с записями. Новое зарезервированное слово object является наиболее очевидным различием, но как мы увидим позднее, имеется большое число других различий, некоторые из которых довольно тонкие
. Производный класс – это новый класс, а базовый класс – существующий класс. Когда вы порождаете один класс из другого (базового класса), производный класс наследует элементы базового класса. Для порождения класса из базового начинайте определение производного класса ключевым словом class, за которым следует имя класса, двоеточие и имя базового класса, например class dalmatian: dog. Когда вы порождаете класс из базового класса, производный класс может обращаться к общим элементам базового класса, как будто эти элементы определены внутри самого производного класса. Для доступа к частным данным базового класса производный класс должен использовать интерфейсные функции базового класса. Внутри конструктора производного класса ваша программа должна вызвать конструктор базового класса, указывая двоеточие, имя конструктора базового класса и соответствующие параметры сразу же после заголовка конструктора производного класса. Чтобы обеспечить производным классам прямой доступ к определенным элементам базового класса, в то же время защищая эти элементы от оставшейся части программы, C++ обеспечивает защищенные (protected) элементы класса. Производный класс может обращаться к защищенным элементам базового класса, как будто они являются общими. Однако для оставшейся части программы защищенные элементы эквивалентны частным. Если в производном и базовом классе есть элементы с одинаковым именем, то внутри функций производного класса C++ будет использовать эле- 11 менты производного класса. Если функциям производного класса необходимо обратиться к элементу базового класса, вы должны использовать оператор глобального разрешения, например base class:: member.
2.3 Экземпляры объектных типов
Экземпляры объектных типов описываются в точности так же, как в Паскале описывается любая переменная, либо статическая, либо указатель, ссылающийся на размещенную в динамической памяти переменную.
Объекты моделируют характеристики и поведение элементов мира, в котором мы живем. Они являются окончательной абстракцией данных.
Не менее важным является и тот факт, что объекты могут наследовать характеристики и поведение того, что мы называем порождающие, родительские объекты (или предки). Здесь происходит качественный скачок: наследование, возможно, является сегодня единственным самым крупным различием между обычным программированием на Паскале и объектно-ориентированным программированием в Borland Pascal.
.
2.4 Поля объектов
Мы можем обратиться к полю объекта в точности так же, как к полю обычной записи, либо с помощью оператора with, либо путем уточнения имени с помощью точки.
Например:
AnHourly.Rate := 9.45;
with AnHourly do
begin
Name := 'Sanderson, Arthur';
Title := 'Word processor';
end;
Примечание: Не нужно забывать о том, что наследуемые поля объектов не интерпретируются особым образом только потому, что они являются наследуемыми.
Надо запомнить, что наследуемые поля являются столь же доступными, как если бы они были объявлены внутри типа объекта.
Например, даже если Name, Title и Rate не являются частью описания типа THourly (они наследованы от типа TEmployee), то вы можете ссылаться на них, словно они описаны в THourly:
AnHourly.Name := 'Arthur Sanderson'.
Выводом из того факта, что методы и их объекты разделяют общую область действия, является то, что формальные параметры метода не могут быть идентичными любому из полей данных объекта. Это является не каким-то новым ограничением, налагаемым объектно-ориентированным программированием, а скорее теми же самыми старымиправилами области действия, которые Паскаль имел всегда. Это тоже самое, что и запрет для формальных параметров процедуры быть идентичными локальным переменным этой процедуры:
procedure CrunchIt(Crunchee: MyDataRec,
Crunchby, ErrorCode: integer);
Var A, B: char;
ErrorCode: integer;
begin
Локальные переменные процедуры и ее формальные параметры совместно используют общую область действия и поэтому не могут быть идентичными. Вы получите сообщение "Error 4: Duplicateidentifier" (Ошибка 4; Повторение идентификатора), если попытаетесь компилировать что-либо подобное, та же ошибка возникает при попытке присвоить формальному параметру метода имени поля объекта, которому данный метод принадлежит.
Обстоятельства несколько отличаются, так как помещение заголовка процедуры внутрь структуры данных является намеком на новшество в Турбо Паскале, но основные принципы области действия Паскаля не изменились.
2.5 Методы
Даже если мы можем обратиться к полям объекта непосредственно, это будет не совсем хорошей идеей. Принципы объектно-ориентированного программирования требуют, чтобы поля объектов были исключены из исходного кода, насколько это возможно. Это ограничение поначалу может показаться спорным и жестким, но оно является только частью огромной картины объектно-ориентированное программирования. Ответ заключается в том, что при всякой возможности для доступа к полям данных должны использоваться методы объекта. Метод является процедурой или функцией, описанной внутри объекта и жестко ограниченной этим объектом.
Методы являются одними из наиболее примечательных атрибутов объектно-ориентированного программирования и требуют некоторой практики перед использованием.
Метод - это процедура или функция, объединенная с данным типом столь тесно, что метод является как бы окруженным невидимым оператором with, что делает экземпляр данного типа доступными изнутри для метода. Определение типа включает заголовок метода. Полное определение метода квалифицируется в имени типа. Тип объекта и метод объекта являются двумя лицами этой новой разновидности структуры, именуемой методом.
Одним из важнейших принципов объектно-ориентированного программирования является то, что программист во время разработки программы должен думать о коде и о данных совместно. Ни код, ни данные не существуют в вакууме. Данные управляют потоком кода, а код манипулирует образами и значениями данных.
Если наш код и данные являются разделенными элементами, то всегда существует опасность вызова правильной процедуры с неверными данными или ошибочной процедуры с правильными данными. Забота о совпадении этих элементов возлагается на программиста, и хотя строгая типизация Паскаля здесь помогает, самое лучшее, что он может сделать - это указать на несоответствие.
Объект осуществляет синхронизацию кода и данных путем совместного построения их описаний. Реально, чтобы получить значение одного из полей объекта, мы вызываем относящийся к этому объекту метод, который возвращает значение нужного поля. Чтобы присвоить полю значение, мы вызываем метод, который назначает данному полю новое значение.
Однако, Borland Pascal не вынуждает нас делать это. Как всякое структурное программирование, объектно-ориентированное программирование является дисциплиной, которую мы должны навязать себе, используя предоставляемые языком средства. Borland Pascal позволяет нам обращаться к полям объекта непосредственно извне объекта, однако он поощряет нас использовать преимущества объектно-ориентированного программирования и создавать методы для манипулирования полями объекта внутри самого объекта.
Итак, подведем некоторый итог. Что такое объект?
Объект состоит из структуры данных и связанных с ней процедур (которые называются методами), которые работают с данными, записанными в экземплярах структуры данных.
Объект может наследовать характеристики порождающего объекта. Это означает, что структура данных нового объекта включает структуру данных порождающего объекта, а также новые данные. Кроме того, новый объект может вызывать все процедуры порождающего объекта, а также те процедуры методов, которые в нем описываются.
Объект, не имеющий наследования, называется базовым объектом. Объект, наследующий характеристики других объектов, называется порожденным или производным объектом.
Тип объекта и метод объекта являются двумя лицами этой новой разновидности структуры, именуемой методом.
type
TEmployee = object
Name, Title: string[25];
Rate: Real;
procedure Init (NewName, NewTitle: string[25];
NewRate: Real);
end;
procedure TEmployee.Init (NewName, NewTitle: string[25];
NewRate: Real);
begin
Name := NewName ; { Поле Name объекта TEmployee }
Title := NewTitle; { Поле Tutle объекта TEmployee }
Rate := NewRate; { Поле Rate объекта TEmployee }
end;
Теперь для инициализации экземпляра типа TEmployee вы просто вызываете его метод, словно метод является полем записи, что имеет вполне реальный смысл:
var
AnEmployee: TEmployee;
AnEmployee.Init('Sara Adams, Account manager, 15000').
2.6. Полиморфизм
Язык программирования поддерживает полиморфизм, если классы с одинаковой спецификацией могут иметь различную реализацию — например, реализация класса может быть изменена в процессе наследования.
Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество реализаций».
Полиморфизм — один из четырёх важнейших механизмов объектно-ориентированного программирования (наряду с абстракцией, инкапсуляцией и наследованием).
Полиморфизм позволяет писать более абстрактные программы и повысить коэффициент повторного использования кода. Общие свойства объектов объединяются в систему, которую могут называть по-разному — интерфейс, класс. Общность имеет внешнее и внутреннее выражение:
внешняя общность проявляется как одинаковый набор методов с одинаковыми именами и сигнатурами (именем методов и типами аргументов и их количеством);
внутренняя общность — одинаковая функциональность методов. Её можно описать интуитивно или выразить в виде строгих законов, правил, которым должны подчиняться методы. Возможность приписывать разную функциональность одному методу (функции, операции) называется перегрузкой метода (перегрузкой функций, перегрузкой операций).
Полиморфный объект представляет собой такой объект, который может изменять форму во время выполнения программы. В объектно-ориентированных языках класс является абстрактным типом данных. Полиморфизм реализуется с помощью наследования классов и виртуальных функций. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения метода, этих методов может быть другой, соответствующей специфике класса-потомка. Другие функции могут работать с объектом класса-родителя, но при этом вместо него во время исполнения будет подставляться один из классов-потомков. Это называется поздним связыванием. Класс-потомок сам может быть родителем. Это позволяет строить сложные схемы наследования – древовидные или сетевидные. Абстрактные (или чисто виртуальные) методы не имеют реализации вообще. Они специально предназначены для наследования. Их реализация должна быть определена в классах-потомках. Класс может наследовать функциональность от нескольких классов. Это называется множественным наследованием. Множественное наследование создаёт проблему (когда класс наследуется от нескольких классов-посредников, которые в свою очередь наследуются от одного класса (так называемая «Проблема ромба»): если метод общего предка был переопределён в посредниках, неизвестно, какую реализацию метода должен наследовать общий потомок. Решается эта проблема через виртуальное
3. Понятие класса
В окончательном виде любая программа представляет собой набор инструкций процессора. Все, что написано на любом языке программирования – более удобная, упрощенная запись этого набора инструкций, облегчающая написание, отладку и последующую модификацию программы. Чем выше уровень языка, тем в более простой форме записываются одни и те же действия. С ростом объема программы становится невозможным удерживать в памяти все детали, и становится необходимым структурировать информацию, выделять главное и отбрасывать несущественное. Этот процесс называется повышением степени абстракции программы. Для языка высокого уровня первым шагом к повышению абстракции является использование функций, позволяющее после написания и отладки функции отвлечься от деталей ее реализации, поскольку для вызова функции требуется знать только ее интерфейс. Если глобальные переменные не используются, интерфейс полностью определяется заголовком функции. Следующий шаг – описание собственных типов данных, позволяющих структурировать и группировать информацию, представляя ее в более естественном виде. Например, все разнородные сведения, относящиеся к одному виду товара на складе, можно представить с помощью одной структуры. Для работы с собственными типами данных требуются специальные функции. Естественно сгруппировать их с описанием этих типов данных в одном месте программы, а также по возможности отделить от ее остальных частей. При этом для использования этих типов и функций не требуется полного знания того, как именно они написаны – необходимы только описания интерфейсов. Объединение в модули описаний типов данных и функций, предназначенных для работы с ними, со скрытием от пользователя модуля несущественных деталей является дальнейшим развитием структуризации программы. Все три описанных выше метода повышения абстракции преследуют цель упростить структуру программы, то есть представить ее в виде меньшего количества более крупных блоков и минимизировать связи между ними. Это позволяет управлять большим объемом информации и, следовательно, успешно отлаживать более сложные программы.
В класс объединяются объекты с одинаковыми свойствами и методами. Введение понятия класса является естественным развитием идей модульности. В классе структуры данных и функции их обработки объединяются. Класс используется только через его интерфейс – детали реализации для пользователя класса не существенны. Идея классов отражает строение объектов реального мира – ведь каждый предмет или процесс обладает набором характеристик или отличительных черт, иными словами, свойствами и поведением. Программы в основном предназначены для моделирования предметов, процессов и явлений реального мира, поэтому удобно иметь в языке программирования адекватный инструмент для представления моделей. Класс является типом данных, определяемым пользователем. В классе задаются свойства и поведение какого-либо предмета или процесса в виде полей данных (аналогично структуре) и функций для работы с ними. Создаваемый тип данных обладает практически теми же свойствами, что и стандартные типы (напомню, что тип задает внутреннее представление данных в памяти компьютера, множество значений, которое могут принимать величины этого типа, а также операции и функции, применяемые к этим величинам). Существенным свойством класса является то, что детали его реализации скрыты от пользователей класса за интерфейсом. Интерфейсом класса являются заголовки его открытых методов. Таким образом, класс как модель объекта реального мира является черным ящиком, замкнутым по отношению к внешнему миру. Идея классов является основой объектно-ориентированного программирования (ООП). Основные принципы ООП были разработаны еще в языках Simula-67 и Smalltalk, но в то время не получили широкого применения изза трудностей освоения и низкой эффективности реализации. В С++ эти концепции реализованы эффективно и непротиворечиво, что и явилось основой успешного распространения этого языка и внедрения подобных средств в другие языки программирования. Идеи ООП не очень просты для практического использования (их неграмотное применение приносит гораздо больше вреда, чем пользы), а освоение существующих стандартных библиотек требует времени и высокого уровня первоначальной подготовки. Конкретные переменные типа данных «класс» называются экземплярами класса, или объектами. Объекты взаимодействуют между собой, посылая и получая сообщения. Сообщение – это запрос на выполнение действия, содержащий набор необходимых параметров. Механизм сообщений реализуется с помощью вызова соответствующих функций. Таким образом, с помощью ООП легко реализуется так называемая «событийно-управляемая модель», когда данные активны и управляют вызовом того или иного фрагмента программного кода. Примером реализации событийно-управляемой модели может служить любая программа, управляемая с помощью меню. После запуска такая программа пассивно ожидает действий пользователя и должна уметь правильно отреагировать на любое из них. Событийная модель является противоположностью традиционной (директивной), когда код управляет данными: программа после старта предлагает пользователю выполнить некоторые действия (ввести данные, выбрать режим) в соответствии с жестко заданным алгоритмом. Класс – это описание определяемого типа. Любой тип данных представляет собой множество значений и набор действий, которые разрешается выполнять с этими значениями. Например, сами по себе числа не представляют интереса – нужно иметь возможность ими оперировать: складывать, вычитать, вычислять квадратный корень и т. д. В С++ множество значений нового типа определяется задаваемой в классе структурой данных, а действия с объектами нового типа реализуются в виде функций и перегруженных операций С++. Данные класса называются полями (по аналогии с полями структуры), а функции класса – методами. Поля и методы называются элементами класса. Описание класса в первом приближении выглядит так: class { [ private: ] public: };// Описание заканчивается точкой с запятой.
Спецификаторы public, private, protected Спецификаторы доступа private и public управляют видимостью элементов класса. Элементы, описанные после служебного слова private, видимы только внутри класса. Этот вид доступа принят в классе по умолчанию. Интерфейс класса описывается после спецификатора public. Действие любого спецификатора распространяется до следующего спецификатора или до конца класса. Можно задавать несколько секций private и public, порядок их следования значения не имеет. Поля класса: могут быть простыми переменными любого типа, указателями, массивами и ссылками (т.е. могут иметь практически любой тип, кроме типа этого же класса, но могут быть указателями или ссылками на этот класс); могут быть константами (описаны с модификатором const), при этом они инициализируются только один раз (с помощью конструктора) и не могут изменяться; могут быть описаны с модификатором static, но не как auto, extern и register. Инициализация полей при описании не допускается.
Глобальные и локальные классы Классы могут быть глобальными (объявленными вне любого блока) и локальными (объявленными внутри блока, например, внутри функции или внутри другого класса). Обычно классы определяются глобально. Локальные классы имеют некоторые особенности: локальный класс не может иметь статических элементов; внутри локального класса можно использовать из охватывающей его области типы, статические (static) и внешние (extern) переменные, внешние функции и элементы перечислений; запрещается использовать автоматические переменные из охватывающей класс области; методы локальных классов могут быть только встроенными (inline); если один класс вложен в другой класс, они не имеют каких-либо особых прав доступа к элементам друг друга и могут обращаться к ним только по общим правилам.
Примеры классов В качестве примера создадим класс, моделирующий персонаж компьютерной игры. Для этого требуется задать его свойства (например, количество щупалец, силу или наличие гранатомета) и поведение. Естественно, пример будет схематичен, поскольку приводится лишь для демонстрации синтаксиса. class monster { int health, ammo; public: monster(int he = 100, int am = 10) { health = he; ammo = am;} void draw(int x, int y, int scale, int position); int get_health(){return health;} int get_ammo(){return ammo;} }. В этом классе два скрытых поля – health и ammo, получить значения которых извне можно с помощью методов get_health() и get_ammo(). Доступ к полям с помощью методов в данном случае кажется искусственным усложнением, но надо учитывать, что полями реальных классов могут быть сложные динамические структуры, и получение значений их элементов не так тривиально. Кроме того, очень важной является возможность вносить в эти структуры изменения, не затрагивая интерфейс класса. Методы класса имеют неограниченный непосредственный доступ к его полям. Внутри метода можно объявлять объекты, указатели и ссылки как своего, так и других классов. В приведенном классе содержится три определения методов и одно объявление (метод draw). Если тело метода определено внутри класса, он является встроенным (inline). Как правило, встроенными делают короткие методы. Если внутри класса записано только объявление (заголовок) метода, сам метод должен быть определен в другом месте программы с помощью операции доступа к области видимости: void monster::draw(int x, int y, int scale, int position) { /* тело метода */} Встроенные методы можно определить и вне класса с помощью директивы inline (как и для обычных функций, она носит рекомендательный характер): inline int monster::get_ammo() { return ammo; } Методы можно перегружать (это одно из проявлений полиморфизма), а также объявлять либо константными, либо статическими (но не одновременно). В каждом классе есть метод, имя которого совпадает с именем класса. Он называется конструктором и вызывается автоматически при создании объекта класса. Конструктор предназначен для инициализации объекта. Автоматический вызов конструктора позволяет избежать ошибок, связанных с использованием неинициализированных переменных. Подробнее конструкторы описываются далее в разделе «Конструкторы». Типы данных struct и union являются специальными видами класса. Конкретные переменные типа данных «класс» называются экземплярами класса, или объектами. Время жизни и видимость объектов зависит от вида и места описания и подчиняется общим правилам С++: monster Vasia; // Объект класса monster с параметрами по умолчанию monster Super(200, 300);// Объект с явной инициализацией monster stado[100]; // Массив объектов с параметрами по умолчанию /* Динамический объект (второй параметр задается по умолчанию) */ monster *beavis = new monster (10); monster &butthead = Vasia;// Ссылка на объект При создании каждого объекта выделяется память, достаточная для хранения всех его полей, и автоматически вызывается конструктор, выполняющий их инициализацию. Методы класса не тиражируются. При выходе объекта из области действия он уничтожается, при этом автоматически вызывается деструктор (деструкторы описаны далее). Доступ к открытым (public) элементам объекта аналогичен доступу к полям структуры. Для этого используются операция . (точка) при обращении к элементу через имя объекта и операция -> при обращении через указатель: объект.поле указатель -> поле (*указатель).поле объект.метод( параметры ) указатель -> метод( параметры ) (*указатель).метод( параметры ) Обращение к открытому полю и вызов метода для массива объектов: имя_массива[ индекс ].поле имя_массива[ индекс ].метод( параметры ) Например: int n = Vasia.get_ammo(); stado[5].draw; cout << beavis->get_health(); Получить или изменить значения private элементов можно только через обращение к соответствующим методам. Можно создать константный объект, значения полей которого изменять запрещается. К нему должны применяться только константные методы: class monster { ... int get_health() const { return health; } }; const monster Dead (0,0); // Константный объект cout << Dead.get_health(); Константный метод: объявляется с ключевым словом const после списка параметров; не может изменять значения полей класса; может вызывать только константные методы; может вызываться для любых (не только константных) объектов. Рекомендуется описывать как константные те методы, которые предназначены для получения значений полей.
Классы могут быть глобальными (объявленными вне любого блока) и локальными (объявленными внутри блока, например, внутри функции или внутри другого класса). Обычно классы определяются глобально.
Локальные классы имеют некоторые особенности: локальный класс не может иметь статических элементов; внутри локального класса можно использовать из охватывающей его области типы, статические (static) и внешние (extern) переменные, внешние функции и элементы перечислений; запрещается использовать автоматические переменные из охватывающей класс области; методы локальных классов могут быть только встроенными (inline) Класс, содержащий хотя бы один чисто виртуальный метод, называется абстрактным.
Абстрактные классы предназначены для представления общих понятий, которые предполагается конкретизировать в производных классах. Абстрактный класс может использоваться только в качестве базового для других классов – объекты абстрактного класса создавать нельзя, поскольку прямой или косвенный вызов чисто виртуального метода приводит к ошибке при выполнении. При определении абстрактного класса необходимо иметь в виду следующее: Абстрактный класс нельзя использовать при явном приведении типов, для описания типа параметра и типа возвращаемого функцией значения. Допускается объявлять указатели и ссылки на абстрактный класс, если при инициализации не требуется создавать временный объект. Если класс, производный от абстрактного, не определяет все чисто виртуальные функции, он также является абстрактным. Таким образом, можно создать функцию, параметром которой является указатель на абстрактный класс. На место этого параметра при выполнении программы может передаваться указатель на объект любого производного класса. Это позволяет создавать полиморфные функции, работающие с объектом любого типа в пределах одной иерархии; если один класс вложен в другой класс, они не имеют каких-либо особых прав доступа к элементам друг друга и могут обращаться к ним только по общим правилам.
4. Процесс объектно-ориентированного проектирования
Объектно-ориентированное проектирование (Object-Oriented Design - OOD) - это поступательный итеративный процесс. Граница между объектно-ориентированным анализом и проектированием расплывчата и построение проекта программного изделия состоит из ряда циклов, в которых уточняются описания классов и взаимодействия между ними, разрабатываются реализующие их программы, проводится их отладка и тестирование и по результатам каждого этапа уточняются рабочие документы предыдущих этапов, дорабатываются описания классов и программы. Эти циклы повторяются до получения требуемого результата.
В рассмотренном выше примере были выделены классы “множество данных” и “данное”. Пусть классу “множество данных” присвоено имя TXSet.
С учетом имеющихся инструментальных средств класс TXSet может быть построен на основе класса Array из библиотеки CLASSLIB, т.е. это множество может быть интерпретировано массивом. Массив представляет собой упорядоченную совокупность однотипных элементов, в то же время данные могут принадлежать различным типам и каждому тип соответствует свой набор характеристик. Это противоречие можно преодолеть, если элементами массива TXSet будут указатели на экземпляры данных.
Чтобы использовать указатели на экземпляры данных как элементы массива, все классы, определяющие типы данных, должны быть образованы из общего базового класса.
Пусть требуется обеспечить возможность использования числовых скалярных данных и массивов (векторов и прямоугольных матриц), а также данных типа строк и массива строк. Естественно определить для каждого такого типа свой класс: TDScal, TDArray, TDString, TDStringArray. В каждом из этих классов должно быть поле идентификатора данного ident, поле описания данного head и, возможно, поле flags, представляющее собой набор битов, дополняющих описание данного. Может оказаться удобным иметь и поля, содержащие количество знаков при представлении скаляра или элементов массивов (width) и количество цифр в дробной части для представления чисел (dec). Все эти данные можно объединить в классе TData, базовом для остальных классов данных. Таким образом, вместо одного класса “данное”, выделенного на этапе анализа, появилось пять классов. После этого следует вернуться к этапу анализа и оформить рабочие документы анализа для новых классов.
Аналогичным образом следует уточнить состав и определения остальных классов, выбранных на этапе анализа.
После определение перечня классов следует разработать семантику каждого класса - определить состав и назначение методов класса. При этом также может возникнуть необходимость выделения новых классов и, следовательно, повторение отдельных частей этапа анализа и новое уточнение ранее описанных классов.
Таким образом, процесс объектно-ориентированного проектирования состоит из циклического выполнения четырех основных шагов:
- Определение классов и объектов на определенном уровне абстракции.
- Определение семантики классов.
- Определение (идентификация) связей между классами и объектами.
- Реализация классов.
На каждом повторении этого цикла уточняются описания классов и перерабатываются проектные документы.
Объектно-ориентированное проектирование--это только часть объектно-ориентированного процесса разработки системы, где на протяжении всего процесса создания ПС используется объектно-ориентированный метод. Этот подход подразумевает выполнение трех этапов:
1. Объектно-ориентированный анализ - создание модели предметной области приложения ПС, где объекты отражают реальные объекты - сущности, а также определяются операции, выполняемые объектами.
2. Объектно-ориентированное программирование -- реализация архитектуры системы с помощью объектно-ориентированного языка программирования непосредственно выполняющего отражение определенных объектов и предоставляющего средства для определения классов объектов.
3. Объектно-ориентированное проектирование -- разработка модели системы программное средство и системной архитектуры с учетом системных требований, в которой определение всех объектов подчинено решению конкретной задачи.
При ООП основное внимание уделяется тому, что следует делать, каким образом добиться цели, а процесс её достижения целиком зависит от этапа разработки. Объектная декомпозиция дает возможность создавать программные комплексы визуально меньшего размера путем использования общих механизмов, обеспечивающих необходимую экономию выразительных средств. Использование объектного подхода повышает уровень унификации разработки и пригодность для повторного использования не только программных компонентов, но и больших комплексов программ, что ведет к созданию унифицированной среды разработки и переходу к сборочному созданию программных продуктов. Системы зачастую получаются более компактными, чем их структурные эквиваленты, что означает не только уменьшение объема программного кода, но и удешевление проекта за счет использования компонентов из предыдущих разработок. Однако, структурный подход сохраняет свою высокую значимость и широко используется на практике. Взаимосвязью между структурным и объектно-ориентированным подходами является общность ряда категорий и понятий жизненного цикла ПС.
В программных средствах при ООП рекомендуется выделять три уровня:
1. Уровень интерфейсов, который занимается всеми взаимодействиями с другими частями системы и предоставлением внешних интерфейсов системы.
2. Уровень сбора данных, управляющий сбором информации из внешней среды и обобщающий данные перед отправкой их в систему построения обобщенных результатов.
3. Уровень объектов, в котором представлены и описаны все объекты, используемые в процессе сбора исходных данных.
5. Объектно-ориентированные языки
Инкапсуляция, наследование и полиморфизм — фундаментальные свойства, требуемые от языка, претендующего называться объектно-ориентированным. (Языки, не имеющие наследования и полиморфизма, но имеющие только классы, обычно называются основанными на классах.) Различные объектно-ориентированные языки используют совершенно разные подходы. Мы можем различать объектно-ориентированные языки, сравнивая механизм контроля типов, способность поддерживать различные программные модели и то, какие объектные модели они поддерживают. Языки объектного программирования принято делить на объектные, в которых существуют классы и объекты, и объектно-ориентированные, в которых программист может не только пользоваться предопределёнными классами, но и задавать собственные пользовательские классы (либо создавать объекты, устройство которых отличается от устройства прототипов — в языках прототипного программирования).
Объектное и объектно-ориентированное программирование возникло в результате развития идеологии процедурного программирования, где данные и подпрограммы (процедуры, функции) их обработки формально не связаны. Кроме того, в современном объектно-ориентированном программировании часто большое значение имеют понятия события (так называемое событийно-ориентированное программирование) и компонента (компонентное программирование).
Объектно-ориентированное программирование в настоящее время является абсолютным лидером в области прикладного программирования (языки Java, C#, C++, JavaScript, ActionScript и др.). В то же время в области системного программирования до сих пор лидирует парадигма процедурного программирования, и основным языком программирования является язык C. Хотя при взаимодействии системного и прикладного уровней операционных систем заметное влияние стали оказывать языки объектно-ориентированного программирования. Например, мультиплатформенным стандартом стала система Qt, написанная на языке C++.
Си++ - это универсальный язык программирования, задуманный так, чтобы сделать программирование более приятным для серьезного программиста. За исключением второстепенных деталей Си++ является надмножеством языка программирования Cи. Помимо возможностей, которые дает Cи, Си++ предоставляет гибкие и эффективные средства определения новых типов. Используя определения новых типов, точно отвечающих концепциям приложения, программист может разделять разрабатываемую программу на легко поддающиеся контролю части. Такой метод построения программ часто называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. Такие объекты просты и надежны в использовании в тех ситуациях, когда их тип нельзя установить на стадии компиляции. При правильном использовании этот метод дает более короткие, проще понимаемые и легче контролируемые программы.
Первым языком программирования, в котором были предложены принципы объектной ориентированности, была Симула. В момент своего появления (в 1967 году), этот язык программирования предложил поистине революционные идеи: объекты, классы, виртуальные методы и др., однако это всё не было воспринято современниками как нечто грандиозное. Тем не менее, большинство концепций были развиты Аланом Кэйем и Дэном Ингаллсом в языке Smalltalk. Именно он стал первым широко распространённым объектно-ориентированным языком программирования.
Различаются чистые и гибридные объектно-ориентированные языки. Чистые — это те, которые позволяют использовать только одну модель программирования — объектно-ориентированную. Вы можете объявлять классы и методы, но не можете завести глобальные переменные и обычные функции и процедуры старого типа.
Среди трех наших языков, только Java(и его клон C#) является чистым объектно-ориентированным языком (как Eiffel и Smalltalk). На первый взгляд это кажется положительной идеей. Однако она ведет к тому, что вы используете кучу статических методов и статических данных, что не так уж отличается от использования глобальных функций и данных, за исключением более сложного синтаксиса. Чистые объектно-ориентированные языки дают преимущество новичкам в объектно-ориентированном программировании, потому что программист вынужден использовать (и учить) модель объектно-ориентированного программирования. C++ и Object Pascal, наоборот, - типичные примеры гибридных языков, которые позволяют программистам использовать при необходимости традиционный подход C или Pascal.
Smalltalk расширяет эту идею до уровня «обобъекчивания» таких предопределенных типов данных, как целые и символы, а также языковых конструкций (таких как циклы). Это теоретически интересно, но сильно уменьшает эффективность. Java останавливается много раньше, допуская присутствие простых не объектно-ориентированных типов данных (хотя имеются необязательные классы-обертки и для простых типов).
6. Особенности объектно-ориентированного проектирования
Третий элемент, по которому различаются языки объектно-ориентированного программирования - их объектная модель. Некоторые традиционные языки объектно-ориентированного программирования позволяют программистам создавать объекты в стеке, в куче (в хипе - heap) или в статической памяти. В этих языках переменная типа класс соответствует объекту в памяти. Так работает C++.
В последнее время появилась тенденция использовать другую модель, часто называемую ссылочно-объектной моделью. В этой модели каждый объект динамически размещается в куче, а переменная типа класс фактически является ссылкой или хэндлом объекта в памяти (технически это нечто вроде указателя). Java и Object Pascal оба используют эту ссылочную модель. Как мы увидим, вкратце это значит, что вам необходимо не забыть выделить память для объекта. Объектно-ориентированный подход использует объектную декомпозицию. При этом статическая структура системы описывается в терминах объектов и связей между ними, а поведение системы описывается в терминах обмена сообщениями между объектами. Каждый объект системы обладает своим собственным поведением, моделирующим поведение объекта реального мира.
Объектно-ориентированное проектирование (ООП) -- это часть объектно-ориентированной методологии, которая предоставляет возможность программистам оперировать понятием «объект», нежели понятием «процедура» при разработке кода.
Общий процесс объектно-ориентированного проектирования состоит из нескольких крупных этапов:
1. Определение рабочего окружения системы и разработка моделей её использования.
2. Проектирование архитектуры программной системы; определение и идентификация основных объектов системы.
3. Разработка модели архитектуры комплекса программ.
4. Определение и документирование интерфейсов объектов.
Процесс объектно-ориентированного проектирование нельзя представить в виде простой схемы, в которой предполагается четкая последовательность этапов.
Как только разработана архитектура системы, определяются объекты и интерфейсы. После создания моделей объектов отдельные объекты можно переопределить, а это может привести к изменениям в архитектуре системы.
Объектно-ориентированное проектирование--это только часть объектно-ориентированного процесса разработки системы, где на протяжении всего процесса создания ПС используется объектно-ориентированный метод. Этот подход подразумевает выполнение трех этапов:
1. Объектно-ориентированный анализ -- создание модели предметной области приложения ПС, где объекты отражают реальные объекты -- сущности, а также определяются операции, выполняемые объектами.
2. Объектно-ориентированное программирование -- реализация архитектуры системы с помощью объектно-ориентированного языка программирования непосредственно выполняющего отражение определенных объектов и предоставляющего средства для определения классов объектов.
3. Объектно-ориентированное проектирование -- разработка модели системы программное средство и системной архитектуры с учетом системных требований, в которой определение всех объектов подчинено решению конкретной задачи.
При ООП основное внимание уделяется тому, что следует делать, каким образом добиться цели, а процесс её достижения целиком зависит от этапа разработки. Объектная декомпозиция дает возможность создавать программные комплексы визуально меньшего размера путем использования общих механизмов, обеспечивающих необходимую экономию выразительных средств. Использование объектного подхода повышает уровень унификации разработки и пригодность для повторного использования не только программных компонентов, но и больших комплексов программ, что ведет к созданию унифицированной среды разработки и переходу к сборочному созданию программных продуктов. Системы зачастую получаются более компактными, чем их структурные эквиваленты, что означает не только уменьшение объема программного кода, но и удешевление проекта за счет использования компонентов из предыдущих разработок. Однако, структурный подход сохраняет свою высокую значимость и широко используется на практике. Взаимосвязью между структурным и объектно-ориентированным подходами является общность ряда категорий и понятий жизненного цикла ПС.
В программных средствах при ООП рекомендуется выделять три уровня:
1. Уровень интерфейсов, который занимается всеми взаимодействиями с другими частями системы и предоставлением внешних интерфейсов системы.
2. Уровень сбора данных, управляющий сбором информации из внешней среды и обобщающий данные перед отправкой их в систему построения обобщенных результатов.
3. Уровень объектов, в котором представлены и описаны все объекты, используемые в процессе сбора исходных данных.
7. Языки и программное окружение
Хотя мы пытались исследовать эти языки, только сравнивая синтаксические и семантические характеристики, важно рассмотреть их в соответствующем контексте. Языки нацелены на различные потребности, что означает, что они решают разные проблемы разными способами и используются в очень разных средах программирования. Хотя как языки, так и их среда копируют характеристики друг друга, они были сконструированы для разных потребностей, и в этом вы можете убедиться, сравнивая их характеристики.
Цель C++ - мощность и контроль за счет сложности. Целью Delphi является легкое, визуальное программирование (не отказываясь от мощности) и прочная связь с Windows. Цель Java - мобильность, даже за счет некоторого отказа от скорости, и распределённые приложения или исполняемое содержание WWW (хотя это, конечно, - не Microsoft-овский взгляд на Java!).
Можно определить, что успех этих трех языков зависит не от технических характеристик, которые я включил в эту статью. Финансовый статус Borland, операционная система управления Microsoft, популярность Sun в мире Internet, тот факт, что Java рассматривается как anti-Microsoft-овский язык, будущее броузеров Паутины и Win32 API, роль и признание модели ActiveX (из-за связанной с ней проблемой безопасности) и три уровня архитектуры Delphi - вот показатели, которые могли повлиять на ваш выбор сильнее, чем технические элементы. Например, такой хороший язык как Eiffel, у которого Object Pascal и Java взяли не только некоторое вдохновение, никогда не получит реальной доли рынка, хотя он был популярен во многих университетах земного шара.
Просто имейте в виду, что "модный" становится все более частым словом в компьютерном мире. Как пользователи хотят иметь инструменты этого года (вероятно, по этой причине операционные системы называются по тому году, в котором они выпущены), программисты любят работать с последним языком программирования и первыми овладеть им. Можно наверняка утверждать, что Java - не последний из языков объектно-ориентированного программирования, через несколько следующих лет найдется кто-то с новым языком.
Заключение
Объектно-ориентированное программирование является в настоящее время основой всей индустрии прикладного программирования благодаря выигрышу в конкурентной борьбе с альтернативными технологиями программирования. В промышленном программировании только в системном программировании позиции объектно-ориентированного программирования еще не очень сильны. Поэтому, с одной стороны, теоретические рассуждения о непригодности объектно-ориентированного программирования не соответствуют наблюдаемой на практике ситуации. С другой стороны, нельзя считать, что объектно-ориентированное программирование во всех случаях является наилучшей из методик программирования.
Процедурное программирование лучше подходит для случаев, когда важны быстродействие и потребляемые ресурсы, объектное - когда важна управляемость проекта и его модифицируемость, а также безопасность программ. Процедурное программирование обычно лучше подходит для небольших проектов, объектное - для больших.
Список литературы
1. Иан Грэхем Объектно-ориентированные методы. Принципы и практика= Object-Oriented Methods: Principles & Practice. — 3-еизд. — М.: «Вильямс», 2004. — С. 880.
2. Антони Синтес Освой самостоятельно объектно-ориентированное программирование за 21 день Sams Teach Yourself Object-Oriented Programming in 21 Days. — М.: «Вильямс», 2002. — С. 672.
3. Бертран Мейер Объектно-ориентированное конструирование программных систем + CD . Интернет-университет информационных технологий - ИНТУИТ.ру, Русская Редакция, 2005
4. Биллиг В.А. Основы программирования на C# . Интернет-университет информационных технологий - ИНТУИТ.ру, 2006
5. “Новые языки программирования и тенденции их развития”, Ушкова В., 2005 г.
6. Объектно – оринтированное программирование - Г.И. Радченко, Е.А. Захаров – Челябинск: Издательский центр ЮУрГУ, 2013. – С. 167.
- Состав и свойства вычислительных систем. Информационное и математическое обеспечение вычислительных систем (Состав вычислительных систем)
- Проектирование организации (на примере ООО «МАРКЕТ ГРУПП»)
- Теории происхождения государства (Теории происхождения государства)
- Контроль за профессиональной деятельностью нотариуса (Место нотариата в правовой системе России и среди органов гражданской юрисдикции)
- Фонд обязательного медицинского страхования РФ
- Понятие и элементы системы кредитования
- Проблемы коммуникаций в современных организациях (Понятие, значение и этапы)
- Проблемы коммуникаций в современных организациях (Теоретический аспект изучения коммуникаций на предприятии)
- Корпоративная культура в организации (Корпоративная культура в мировой практике)
- Выбор стиля руководства в организации (Основные стили руководства)
- Внедрение процессного подхода к управлению в организации
- Корпоративная культура в организации