Класс в объектно ориентированном программировании
Классы и объекты
В данном уроке мы рассмотрим классы в C++ и познакомимся с объектно-ориентированным программированием. Объектно-ориентированное программирование или ООП — это одна из парадигм программирования. Парадигма — это, другими словами, стиль. Парадигма определяет какие средства используются при написании программы. В ООП используются классы и объекты. Все наши предыдущие программы имели элементы разных парадигм: императивной, процедурной, структурной.
Мы можем написать одинаковую программу в разных парадигмах. Парадигмы не имеют чёткого определения и часто пересекаются.
Давайте посмотрим на пример. Допустим, в нашей игре есть танки и они могут стрелять, при стрельбе у них уменьшается боезапас. Как мы можем это смоделировать без ООП:
У нас есть структура, которая содержит поле, представляющее количество снарядов, и есть функция атаки, в которую мы передаём танк. Внутри функции мы меняем количество снарядов. Так может выглядеть игра на языке C: структуры отдельно от функций, которые совершают действия со структурными переменными. Данную ситуацию можно смоделировать по-другому с помощью объектно-ориентированного программирования (Object-Oriented Programming, OOP) — ООП.В ООП действия привязываются к объектам.
Определение классов в C++
Класс — это пользовательский тип данных (также как и структуры). Т.е. тип данных, который вы создаёте сами. Для этого вы пишете определение класса. Определение класса состоит из заголовка и тела. В заголовке ставится ключевое слов class, затем имя класса (стандартный идентификатор C++). Тело помещается в фигурные скобки. В C++ классы и структуры почти идентичны. В языке C в структурах можно хранить только данные, но в C++ в них можно добавить действия.
В C++ ключевые слова struct и class очень близки и могут использоваться взаимозаменяемо. У них есть только одно отличие (об этом ниже). Вот как можно определить такой же класс с помощью struct:
Отличие только первом ключевом слове. В одном из прошлых уроков мы уже обсуждали структуры. что мы видим новое? Ключевые слова private и public — это спецификаторы доступа. Также мы видим, что внутри класса мы можем вставлять определения функций.
Определение класса это чертёж. Оно говорит нам из каких данных состоит класс и какие действия он может совершать. т.е. происходит объединение данных и действий в одной сущности.
Переменные и методы класса
Класс состоит из членов класса (class members). Члены класса могут быть переменными (data members) или методами (function members или methods). Переменные класса могут иметь любой тип данных (включая другие структуры и классы). Методы — это действия, которые может выполнять класс. По сути, это обычные функции.
Все методы класса имеют доступ к переменным класса. Обратите внимание, как мы обращаемся к ammo в методе Attack.
Создание объектов класса
Теперь у нас есть свой тип данных и мы можем создавать переменные данного типа. Если после определения структур мы могли создавать структурные переменные, то в случае классов, мы создаём объекты классов (или экземпляры). Разница между классами и структурами только в терминах. Для C++ это почти одно и то же.
Вот так мы можем создать объекты класса Tank и вызвать метод Attack:
t1 и t2 — объекты класса Tank. Для C++ объект класса — это всего-лишь переменная. Тип данных этих переменных — Tank. Ещё раз повторю, что классы (и структуры) позволяют создавать пользовательские типы данных.
В англоязычной литературе создание объектов классов также называется созданием экземпляров — instantiating.
Мы обращаемся к переменным класса и методам с помощью оператора точки (прямой доступ), также как мы обращались к полям структурных переменных.
В нашем примере каждый объект имеет доступ к своей копии ammo. ammo — переменная класса (data member). Attack — метод класса. У каждого объекта своя копия переменных класса, но все объекты одного класса вызывают одни и те же методы.
Размер объекта включает все данные, но не методы
В памяти переменные класса располагаются последовательно. Благодаря этому мы можем создавать массивы объектов и копировать их все вместе (если в классе этих объектов нет динамического выделения памяти). Это будет важно для нас, когда мы начнём работать с графикой в DirectX/OpenGL. Размер объекта класса можно узнать с помощью функции sizeof. При этом в качестве аргумента можно использовать как объект, так и сам класс:
Методы — это все лишь функции. Но в отличии от простых функций, у всех методов есть один скрытый параметр — указатель на объект, который вызывает данный метод. Именно благодаря этому указателю метод знает, какой объект вызвал его и какому объекту принадлежат переменные класса. Внутри метода имя этого указателя — this.
Указатель this
Вот как для компилятора выглядит любой метод:
Это просто иллюстрация. В реальности не нужно указывать аргумент (всё что в круглых скобках). Мы автоматически получаем доступ к указателю this. В данном случае его использование перед ammo необязательно, компилятор автоматически привяжет эту переменную к this.
Указатель this нужен, когда методу необходимо вернуть указатель на текущий объект.
Указатели на объекты
При работе с объектам в C++ вам неизбежно придётся работать с указателями (и ссылками). Как мы помним, при передаче в функцию по значению создаётся копия переменной. Если у вас сложный класс, содержащий большой массив или указатели, то копирование такого объекта может потребовать ненужное выделение дополнительной памяти или может быть вообще невозможным, в случае если в классе вы динамически выделяете память. Поэтому очень часто объекты создаются динамически. Для доступа к таким объектам используется оператор непрямого доступа (стрелочка):
При использовании ссылки на объект, для доступа к его членам используется оператор прямого доступа (точка), т.е. с ссылкой можно обращаться как с обычным объектом:
Чуть ниже мы увидим один случай, когда не обойтись без ссылок.
Конструктор класса (Constructor)
Конструктор класса — метод, вызываемый автоматически при создании объекта. Он используется для инициализации переменных класса и выделении памяти, если это нужно. По сути это обычный метод. Имя обязательно должно совпадать с именем класса и он не имеет возвращаемого значения. Рассмотрим новый класс:
Здесь, в конструкторе задаются начальные значения переменных, но мы можем делать в нём всё что угодно, это обычная функция.
Перегрузка конструктора класса
Перегрузка (overloading) конструктора позволяет создать несколько конструкторов для одного класса с разными параметрами. Всё то же самое, что и при перегрузке функций:
Начальные значения можно задавать в виде списка инициализации. Выше в конструкторе мы инициализировали переменные внутри тела. Список инициализации идёт перед телом конструктора и выглядит так:
В списке инициализации можно задать значение только части переменных класса.
Копирующий конструктор (Copy Constructor)
Без каких-либо действий с нашей стороны мы можем присваивать объектам другие объекты:
Здесь используется копирующий конструктор. Копирующий конструктор по умолчанию просто копирует все переменные класса в другой объект. Если в классе используется динамическое выделение памяти, то копирующий конструктор по умолчанию не сможет правильно создать новый объект. В таком случае вы можете перегрузить копирующий конструктор:
В копирующем конструкторе всегда используются ссылки. Это обязательно. Параметр point — это объект, стоящий справа от оператора присваивания.
Деструктор класса
Деструктор класса — метод, вызываемый автоматически при уничтожении объекта. Это происходит, например, когда область видимости объекта заканчивается. Деструктор нужно писать явно, если в классе происходит выделение памяти. Соответственно, в деструкторе вам необходимо освободить все указатели.
Допустим в нашем танке есть экипаж, пусть это будет один объект типа Unit. При создании танка мы выделяем память под экипаж. В деструкторе нам нужно будет освободить память:
Имя деструктора совпадает с именем класса и перед ним ставится тильда
. Деструктор может быть только один.
Объектно-ориентированное программирование в C++ (ООП)
Теперь, когда мы представляем что такое классы и объекты, и умеем с ними работать, можно поговорить о объектно-ориентированном программировании. Сам по себе стиль ООП предполагает использование классов и объектов. Но помимо этого, у ООП есть ещё три характерные черты: инкапсуляция данных, наследование и полиморфизм.
Инкапсуляция данных — Encapsulation
Что означает слово Encapsulation? Корень — капсула. En — предлог в. Инкапсуляция — это буквально помещение в капсулу. Что помещается в капсулу? Данные и действия над ними: переменные и функции. Инкапсуляция — связывание данных и функций. Давайте ещё раз взглянем на класс Tank:
Собственно, здесь в класс Tank мы поместили переменную ammo и метод Attack. В методе Attack мы изменяем ammo. Это и есть инкапсуляция: члены класса (данные и методы) в одном месте.
В C++ есть ещё одно понятие, которое связано с инкапсуляцией — сокрытие данных. Сокрытие предполагает помещение данных (переменных класса) в область, в которой они не будут видимы в других частях программы. Для сокрытия используются спецификаторы доступа (access specifiers). Ключевые слова public и private и есть спецификаторы доступа. public говорит, что весь следующий блок будет видим за пределами определения класса. private говорит, что только методы класса имеют доступ к данным блока. Пример:
Здесь мы видим, что объект может получить доступ только к членам класса, находящимся в блоке public. При попытке обратиться к членам класса (и переменным, и методам) блока private, компилятор выдаст ошибку. При этом внутри любого метода класса мы можем обращаться к членам блока private. В методе Move мы изменяем скрытые переменные x и y.
Хороший стиль программирования в ООП предполагает сокрытие всех данных. Как тогда задавать значения скрытых данных и получать доступ к ним? Для этого используются методы setters и getters.
Setters and Getters
Setters и Getters сложно красиво перевести на русский. В своих уроках я буду использовать английские обозначения для них. Setter (set — установить) — это метод, который устанавливает значение переменной класса. Getter (get — получить) — метод, который возвращает значение переменной:
Имена не обязательно должны включать Set и Get. Использование setters и getters приводит к увеличению количества кода. Можно ли обойтись без инкапсуляции и объявить все данные в блоке public? Да, можно. Но данная экономия кода имеет свои негативные последствия. Мы будем подробно обсуждать данный вопрос, когда будем говорить об интерфейсах.
Следующая концепция ООП — наследование.
Наследование (Inheritance) в C++
Производный класс не может получить доступ к private членам. Поэтому в классе Unit используется спецификатор protected. Данный спецификатор разрешает доступ к данным внутри класса и внутри дочерних классов, private же разрешает доступ только в методах самого класса.
При наследовании производный класс имеет доступ ко всем членам (public и protected) базового класса. Именно поэтому мы можем вызвать метод Move для объекта типа Archer.
Обратите внимание, как происходит наследование. При определении дочернего класса, после имени ставится двоеточие, слово public и имя базового класса. В следущем уроке мы рассмотрим для чего здесь нужно слово public.
Полиморфизм (Polymorphism)
Наследование открывает доступ к полиморфизму. Poly — много, morph — форма. Это очень мощная техника, которую мы будем использовать постоянно.
Полиморфизм позволяет поместить в массив разные типы данных:
Мы создали массив указателей на Unit. Но C++ позволяет поместить в такой указатель и указатель на любой дочерний классс. Данная техника будет особенно полезна, когда мы изучим виртуальные функции.
Заключение
Классы позволяют легко моделировать лубую предметную область. Иногда лучше избежать использование ООП, но об этом мы поговорим в другой раз.
В следующем уроке мы познакомимся с более сложными концепциями, касающимися классов: виртуалье методы, шаблоны, статичные члены. Впоследствии мы увидим, как классы используютя в DirectX.
Единственное отличие между классом и структурой в C++: по умолчанию в структуре используется спецификатор доступа public, а в классе — private. Часто в коде вы будете видеть, что структуры используются без методов, чисто для описания каких-либо сущностей. Но это делать необязательно это всего лишь соглашение.
ITandLife.ru
Статьи об IT, программировании, политике, экономике, жизни и изучении научных дисциплин
Классы в ООП (Объектно-ориентированном программировании)
Эта статья — продолжение серии статей об ООП. В прошлой публикации были рассмотрено «понятие объекта в ООП». В этой заметке будут описаны классы. Это довольно сложная тема, рассмотрение которой подразумевает что Вы знакомы с понятием объекта в объектно-ориентированном программировании.
Понятие класса в ООП
В любой системе функционирует множество объектов. Некторые из них «похожи» и однотипны. Например, в банковской системе имеется множество объектов-счетов и объектов-клиентов. Однотипные объекты объединяются в классы.
Все объекты одного и того же класса обладают одинаковым интерфейсом и реализуют этот интерфейс одним и тем же способом. Два объекта одного класса в ООП могут отличаться только текущим состоянием, причем всегда теоретически возможно так изменить состояние одного объекта, чтобы он стал равным другому объекту.
Например, продолжая примеры прошлой статьи, у всех объектов-счетов, принадлежащих к классу «Счет», имеется номер и баланс, все они реагируют на сообщение «проверить наличие денег и снять сумму со счета». Важно, что реагируют они на это сообщение одинаково, т.е. реализация метода у всех объектов одного класса одинакова.
Индивидуальные объекты называются экземплярами класса, а класс в ООП — это шаблон по которому строятся объекты.
Таким образом, наша банковская система состоит из экземпляров трех классов: класса счетов, класса банкоматов и класса клиентов. Названия классов в ООП пишутся с большой буквы, а названия объектов — с маленькой. Представленная ниже графическая схема классов соответствует обозначениям, принятым в Унифицированном языке моделирования UML.
Классы в учебной банковской системе
В реальности же, счета могут быть различными. Срочный вклад отличается от расчетного и от вклада до востребования. У них имеются разные характеристики, и они по-разному реализуют одни и теже операции. Поэтому для их описания нужны разные классы.
Разделение счетов на разные классы
Чем отличается понятие класса в ООП от таких понятий как «интерфейс» или «тип»?
Интерфейс — это внешняя часть класса. Интерфейс определяет, как объекты данного класса могут взаимодействовать с другими объектами этого или других классов. Однако, если у двух объектов совпадают интерфейсы это еще не значит что они принадлежат к одному и тому же классу. Кроме совпадения интерфейсов необходимо, чтобы и их реализация и поведение были одинаковыми.
Тип — это область определения некой величины, т.е. множество ее возможных значений и набор применимых операций. Тип может задаваться классом.
Наследование классов в ООП
Важнейшим свойством классов в ООП и их принципиальным отличием от абстрактных типов данных (встроенных в язык программирования) является наследование. Наследование — это отношение между классами, при котором один класс разделяет структуру или поведение одного или нескольких других классов.
Механизм наследования классов в ООП позволяет выделить общие части разных классов. В приведенном выше примере, были выделены разные типы счетов в банковской системе. Однако они имеют много общего. Выделив общую часть, можно создать класс «Счет». Классы «Расчетный счет» и «Депозит» сохраняют все свойства (как методы, так и атрибуты) класса «Счет», дополняя и уточняя его поведение. Говорят что класс «Депозит» наследует класс «Счет». Графически это изображается в виде иерархии.
Схема наследования классов-счетов
Наследование классов в ООП может быть многоуровневым. Пример такой многоуровневой структуры классов-счетов представлен ниже.
Схема многоуровневого наследования классов
Иерархию классов в ООП можно построить по-разному. Фактически иерархия классов является классификатором объектов. В данном случае при построении системы классов разработчик пытается принять во внимание следующие соображения «Столь ли существенна разница между рублевыми и валютными вкладами, что их следует разделить на различные классы?», «Разные виды Депозитов — это разные характеристики одного и того же класса или же разные классы?» и т.п.
Как видно из рисунка, представленного выше, разница между рублевым и валютным счетом настолько существенна, что они выделены в разные классы. Разные виды Депозитов также представлены разными классами. Если бы решили, что денежная единица, в которой выражается сумма на счете, — лишь дополнительны атрибут счета, и разные типы депозитов различаются дополнительной характеристикой класса «Депозит», то иерархия классов преобразовалась бы к виду, изображенному на рисунке:
Упрощенная иерархия валютных и рублевых счетов
Важно отметить, что в ООП существует особый тип классов — абстрактные классы. Абстрактные классы — это классы для которых не существует экземпляров, они лишь описывают общие характеристики классов-потомков. В нашем случае абстрактным классом можно считать класс «Счет», т.к. фактически экземпляров данного класса не существует. Зато он используется для реализации общего интерфейса для классов-потомков.
Конкретные классы — это классы экземпляры которых могут существовать (или существуют) в системе в отличии от абстрактных классов.
Механизм абстрактных классов в ООП является чрезвычайно мощным понятием, которое широко используется. Назначением абстрактных классов в ООП является определение общих, наиболее характерных методов и атрибутов наследуемых из них классов. Чаще всего абстрактные классы используются для задания общего интерфейса иерархии конкретных классов, хотя и атрибуты, и реализация каких-либо методов могут присутствовать в абстрактных классах.
Рассмотренные до сих пор примеры показывали как класс в ООП может унаследовать методы и атрибуты одного базового класса. Такое наследование носит название одинарного или простого наследования. Наряду с ним существует и множественное наследование, при котором у одного класса имеется несколько базовых.
Множественное наследование в ООП позволяет объединять характеристики различных классов в одном. Мы рассмотрели иерархию классов для представления счетов в банковской системе, которая отображает функциональные характеристики счетов — возможности пожить или снять деньги со счета. С другой стороны, при реализации этой банковской системы многие объекты, в том числе и счета, должны храниться в базе данных. Система классов, обеспечивающая хранение объектов в базе данных, может состоять из базового класса «Постоянный объект», у которого есть методы сохранить и извлечь для реализации записи и чтения из базы данных, а атрибуты «имя таблицы» и «номер строки» для описания местоположения объекта. Для того чтобы какой-либо конкретный счет стало возможным хранить в базе данных, он должен быт выведен из класса «Постоянный объект».
Класс «Валютный депозит» наследует атрибуты и методы обоих своих родителей.
Полиморфизм в ООП
Полиморфизм — это возможность взаимодействия с объектом, не зная, к какому конкретному классу он относится. Например, посылая сообщение любому счету мы используем полиморфизм всех счетов.
В данном случае полиморфизм является ограниченным. Если сообщение «снять» будет послано, например, клиенту, он не сможет его обработать, т.е. нам не важно какой конкретно счет обрабатывает сообщение, но тем не менее это должен быть счет, объект одного из классов, выделенных из базового класса «Счет».
В большинстве случаев используется именно ограниченный полиморфизм. Тем не менее, иногда любой объект системы может обработать некоторое сообщение. Например, в языке Java у всех объектов имеется метод toString, приводящий значение объекта к строковому виду, соответственно любому объекту независимо от его класса можно послать сообщение toString.
При использовании полиморфизма в ООП используется знание интерфейса объекта, однако поведение конкретного объекта в ответ на полученное сообщение может быть различно в зависимости от конкретного класса этого объекта. Соответственно посылающий сообщение объект точно не знает, что произойдет при вызове метода.
Навигация по записям
Классы в ООП (Объектно-ориентированном программировании) : 4 комментария
Мне понравилось изложение материала.
Только не хватает ссылки на следующую статью.
- M_a_Ge Автор записи 14 июля 2012 в 12:20
Спасибо. Надеюсь что скоро продолжу публикации по этой теме.
Спасибо большое за такой отличный материал. Наконец-то нашла простое изложение, очень помогло. Всё разъяснили)
Очень хорошо и понятно всё изложено.
Перед этим освоил статью про Объект.
Большое спасибо за такое классное изложение, я действительно понял что такое объект, метод и класс, а так же тонкости классов что описаны в этой статье.
По возможности буду рекомендовать Ваши статьи в качестве учебного пособия для двух знакомых преподавателей по ооп.
Класс (ООП)
Класс, наряду с понятием «объект», является важным понятием объектно-ориентированного подхода в программировании (хотя существуют и бесклассовые объектно-ориентированные языки, например, Прототипное программирование). Под классом подразумевается некая сущность, которая задает некоторое общее поведение для объектов. Таким образом, любой объект может принадлежать или не принадлежать определенному классу, то есть обладать или не обладать поведением, которое данный класс подразумевает. Класс определяет для объекта контракт, то есть правила, с помощью которых с объектом могут работать другие объекты (обычно это делается с помощью определения методов класса). Кроме того классы могут находиться друг с другом в различных отношениях, таких как наследование или агрегация.
Фактически объектно-ориентированное программирование чаще всего сводится к созданию некоторого количества классов, описанию связей между этими классами и их свойств, и дальнейшей реализации полученных классов. Графическое представление некоторого количества классов и связей между ними называется диаграммой классов. Объектно-ориентированный подход за время своего развития накопил множество рекомендаций (паттернов) по созданию классов и иерархий классов.
Содержание
Теоретический подход
Класс — это один из вариантов описания сущности, которая в теории программирования именуется абстрактным типом данных. Класс определяет скрытую внутреннюю структуру некоторого значения, а также набор операций, применимых к данному значению. Первая определяется как набор полей класса — элементов тех или иных ранее определённых типов, вторая — как набор сообщений, которые могут обрабатываться экземплярами данного класса. Множество всех возможных сочетаний значений полей класса создаёт множество значений абстрактного типа. Вторая часть определения в современных языках программирования представляет собой набор публичных методов, то есть связанных с классом функций, имеющих доступ к его внутренней структуре, но доступных извне класса.
Экземпляр класса, в этом случае — значение абстрактного типа, заданного классом. Все экземпляры имеют одну и ту же внутреннюю структуру, заданную описанием класса, и один и тот же интерфейс (контракт) — набор применимых к ним операций. В другой терминологии, конкретный набор значений полей класса в данном экземпляре есть внутреннее состояние объекта, а интерфейс класса определяет его поведение.
Практический подход
В современных объектно-ориентированных языков программирования (в том числе в php, Oberon, Ruby, Object Pascal) создание класса сводится к написанию некоторой структуры, содержащей набор полей и методов (среди последних особую роль играют конструкторы, деструкторы, финализаторы). Практически класс может пониматься как некий шаблон, по которому создаются объекты — экземпляры данного класса. Экземпляры одного класса созданы по одному шаблону, поэтому имеют один и тот же набор полей и методов.
Отношения между классами
- Наследование (Генерализация) — объекты дочернего класса наследуют все свойства родительского класса.
- Ассоциация — объекты классов вступают во взаимодействие между собой.
- Агрегация — объекты одного класса входят в объекты другого.
- Композиция — объекты одного класса входят в объекты другого и зависят друг от друга по времени жизни.
- Класс-Метакласс — отношение, при котором экземплярами одного класса являются другие классы.
Виды классов
- Базовый (родительский) класс
- Производный класс (наследник, потомок)
- Абстрактный класс
- Виртуальный класс
- Интерфейс
Эти виды классов описаны в статье Наследование, так как связаны именно с этим отношением.
Члены классов
Класс определяется как список своих членов. К членам класса относятся его поля (свойства) и функции (методы) .
Каждому члену класса можно установить его область доступа (access control level). Область доступа члена класса определяет участки кода, из которых к этому члену будет возможно обращаться. В большинстве объектно-ориентированных языков программирования поддерживаются следующие области доступа:
- private (закрытый, внутренний член класса) — обращения к члену допускаются только из кода методов класса, в котором этот член определён. Любые наследники класса уже не смогут получить доступ к этому члену;
- protected (защищённый, внутренний член иерархии классов) — обращения к члену допускаются из кода методов класса, в котором этот член определён, или из любых его классов-наследников;
- public (открытый член класса) — обращения к члену допускаются из любого кода.
Область видимости
Область видимости членов класса (то есть область кода, из которой к ним можно обращаться по неквалифицированному имени — без указания имени класса или объекта) не зависит от их области доступа, и всегда совпадает с кодом методов класса.
Область видимости самого класса по-разному определяется в разных языках программирования. В одних языках (таких как модуля), в других (таких как пакетом), в третьих (таких как C++ и C#) область видимости класса определяется пространствами имён (namespaces), которые задаются программистом явно и могут совпадать или не совпадать с единицами компиляции.
Классы в языке Delphi
На языке Delphi класс описывается следующим образом:
- TMyClass — имя класса;
- class — ключевое слово, начинающее определение класса;
- TObject — класс-предок, если есть наследование;
- private, protected, public, published — ключевые слова, обозначающие секции областей доступа.
Создается экземпляр (объект) класса так:
Классы в языке C++
Класс в языке C++ создаётся следующим образом:
После своего создания класс считается полноценным типом данных и, следовательно экземпляры класса создаются следующим образом:
Обращение к членам класса:
Уничтожается экземпляр класса, как и любая переменная, только в случае, если функция, в которой он был создан завершила работу или если была принудительно освобождена динамическая память, выделенная под класс.
Классы в языке C Sharp
Классы в языке C# определятся следующим образом:
Классы в языке Python с помощью оператора class :
Создание экземпляра класса:
Уничтожение экземпляра класса:
Классы в языке Java с помощью оператора class :
Создание экземпляра класса:
Уничтожение экземпляра класса:
Ссылки
- Creating Classes — Руководство по созданию классов в языке Классы — PPT-файл одной из лекций курса «Объектно-ориентированный анализ и дизайн»
См. Также
Wikimedia Foundation . 2010 .
Смотреть что такое «Класс (ООП)» в других словарях:
Класс (программирование) — У этого термина существуют и другие значения, см. Класс. Класс в программировании набор методов и функций. Другие абстрактные типы данных метаклассы, интерфейсы, структуры, перечисления характеризуются какими то своими, другими… … Википедия
Интерфейс (ООП) — Интерфейс (от лат. inter между и лат. face поверхность) это семантическая и синтаксическая конструкция в коде программы, используемая для специфицирования услуг, предоставляемых классом или компонентом. Интерфейс определяет границу… … Википедия
Хрупкий базовый класс — Хрупкий базовый класс фундаментальная проблема объектно ориентированного программирования. Описание Проблема хрупкого базового класса заключается в том, что малейшие правки в деталях реализации базового класса могут привнести ошибку в… … Википедия
Абстрактный класс — в объектно ориентированном программировании базовый класс, который не предполагает создания экземпляров. Абстрактные классы реализуют на практике один из принципов ООП полиморфизм. Абстрактный класс может содержать (и не содержать[1]) абстрактные … Википедия
Вспомогательный класс (информатика) — Вспомогательный класс (англ. Helper Class) метод программирования в ООП, который не рекомендуется использовать[кем?]. Вспомогательный класс термин, применяемый к классу, который используется для помощи в реализации некоторой… … Википедия
ActionScript — Класс языка: Объектно ориентированный, Императивный, скриптовый Появился в: 1998 Автор(ы): Гари Гроссман … Википедия
Объектно-ориентированное программирование — Эта статья во многом или полностью опирается на неавторитетные источники. Информация из таких источников не соответствует требованию проверяемости представленной информации, и такие ссылки не показывают значимость темы статьи. Статью можно… … Википедия
ООАП — Объектно ориентированное программирование (ООП) парадигма программирования, в которой основными концепциями являются понятия объектов и классов (либо, в менее известном варианте языков с прототипированием прототипов). Класс это тип, описывающий… … Википедия
Объектно-ориентированный подход — Объектно ориентированное программирование (ООП) парадигма программирования, в которой основными концепциями являются понятия объектов и классов (либо, в менее известном варианте языков с прототипированием прототипов). Класс это тип, описывающий… … Википедия
Полиморфизм (программирование) — У этого термина существуют и другие значения, см. Полиморфизм. Эта статья или раздел нуждается в переработке. Пожалуйста, улучшите статью … Википедия
Что такое классы в объектно-ориентированном программировании
В этом цикле статей мы говорим об объектно-ориентированном программировании — передовом и очень распространённом подходе к разработке. Это стоит знать всем, кто серьёзно относится к программированию и хочет зарабатывать в этой области.
Если не читали предыдущую статью, вот краткое содержание:
- ООП — это подход к программированию. Такой набор практик и принципов, которыми пользуются хорошие разработчики. Противопоставление этому подходу — традиционное процедурное программирование.
- В процедурном программировании мы пишем функции, которые выполняют какие-то задачи. И при необходимости вызываем одни функции из других. В программе функции живут отдельно, данные — отдельно.
- Главная проблема процедурного программирования — сложно писать и поддерживать большие проекты. Любой мало-мальски сложный продукт будет требовать сотен функций, которые будут связаны между собой. Получится «спагетти-код».
- В ООП функции и данные группируются в объекты. Объекты более-менее независимые и общаются друг с другом по строго определённым правилам.
- Данные в ООП хранятся внутри объектов и называются свойствами объектов. Например, у объекта user может быть свойство name со значением ‘Иван’.
- Функции в ООП тоже хранятся внутри объектов и называются методами объектов. Например, у объекта user может быть метод sendEmail(), который отправляет этому юзеру письмо.
- Можно представить, что в ООП взяли «спагетти-код» с тефтелями и разложили из огромного чана порционно по контейнерам. Теперь в каждом контейнере есть спагетти и тефтели, и каждый программист может работать над своим контейнером-объектом, а не ковыряться в общем чане со спагетти.
Одно из преимуществ ООП — не нужно много раз писать один и тот же код. Можно однажды придумать какую-то красивую штуку и потом заново её использовать буквально одной строкой. Для этого и нужны классы.
Что за классы
Вот одно из формальных определений класса: «Класс — это элемент ПО, описывающий абстрактный тип данных и его частичную или полную реализацию»
Если более по-русски, то класс — это шаблон кода, по которому создаётся какой-то объект. Это как рецепт приготовления блюда или инструкция по сборке мебели: сам по себе класс ничего не делает, но с его помощью можно создать новый объект и уже его использовать в работе.
Если пока непонятно, погружайтесь в пример:
Призовём на помощь силу примеров и поговорим про сотовые телефоны.
Допустим, вы делаете мобильники и хотите выпустить на рынок новую модель. Чтобы люди могли сразу пользоваться вашим устройством и быстро к нему привыкли, у телефона должен быть экран, кнопки включения и громкости, камеры спереди и сзади, разъём для зарядки и слот для сим-карты.
Но одного железа недостаточно — нужно соединить его между собой так, чтобы всё работало без сбоёв. Кроме этого, нужно предусмотреть, что происходит при нажатии на кнопки, что выводится на экран и как пользователь будет управлять этим телефоном.
Следующий этап — описать каждую деталь, из которой состоит телефон, каждую микросхему и плату, и объяснить, как детали работают друг с другом. Последний шаг — написать руководство пользователя, где будет полностью рассказано, что можно делать с телефоном, как запустить звонилку или отправить смс.
Мы только что сделали новый класс для телефона — полный набор нужных знаний, описаний, свойств и инструкций, который описывает нашу модель. Все эти инструкции и описания — это ещё не телефон, но из них этот телефон можно сделать.
В программировании у класса есть наборы данных — в нашем случае это комплектующие для телефона. Ещё есть функции для работы с классами, которые называются методами — это то, как пользователь будет работать с нашим телефоном, что он будет на нём делать и каким образом.
Классы на практике
Все примеры дальше мы будем делать на Python, потому что это стильно, модно и молодёжно. А сам Python — очень объектно-ориентированный язык, почти всё в нём — это объекты. Вот и опробуем.
Допустим, мы пишем интернет-магазин с системой скидок. Нам нужно работать с пользователями — постоянными покупателями. Пользователь у нас будет объектом: у него будет имя, возраст и адрес доставки по умолчанию. Мы заведём класс, который поможет нам инициировать нового покупателя.
Здесь сказано: «Вот класс для покупателя. У него есть три свойства: имя, возраст и адрес». Теперь мы можем заводить новых покупателей одной строкой:
# Создаём первого покупателя
# Создаём второго покупателя
Что дальше
В следующем материале мы смоделируем реальную ситуацию: добавим программу лояльности, бонусные баллы и расскажем, как Python с этим справится. Чтобы было интереснее, будем писать код на двух языках сразу — Python и JavaScript.
Классы ООП. Объектно-ориентированное программирование
Термины «объект» и «класс» знакомы каждому человеку. Однако для компьютерщиков они имеют свой подтекст. Это основные понятия в объектно-ориентированном программировании. Классы — определяемый разработчиком тип данных, который характеризуется способом их передачи и хранения, профилем использования и набором действий, которые могут с ними производиться. Они отличаются тем, что могут реализовываться в качестве интерфейса.
Что такое ООП (объектно-ориентированное программирование)
Опытные разработчики хорошо знают языки COBOL и C. Написанные на них программы представляли собой последовательность пошаговых инструкций. Они использовали процедуры и функции для того, чтобы сделать программу модульной. Эта парадигма была сосредоточена на логике, а не на данных, и на методах их объединения.
Современные языки программирования Delphi, Java, C# и другие следуют объектно-ориентированному подходу. При этом важность отдается данным, а не просто написанию инструкций для выполнения задачи. Объект — это вещь или идея, которую вы хотите смоделировать. Им может быть что угодно, например, сотрудник, банковский счет, автомобиль, различные предметы обстановки и так далее.
Понятие объектно-ориентированного программирования (ООП) неотъемлемо связано со следующими критериями:
- Абстракция.
- Инкапсуляция.
- Наследование.
- Полиморфизм.
Рассмотрим каждый из них более подробно.
Абстракция
Этот критерий позволяет сосредоточиться на том, что делает сам объект, но не на том, какими способами эти действия реализуются при программировании. ООП подразумевает, что абстракция — это знание об объекте максимального количества данных. Она помогает в создании независимых модулей, которые могут взаимодействовать друг с другом некоторыми способами.
Мы стараемся выборочно сосредоточиться только на тех вещах, которые важны для нас (в жизни) или для нашего модуля (в программировании). Изменение одного независимого модуля не влияет на другие. Единственное, что нужно знать, — это то, что он нам дает. Человек, который использует этот модуль, не должен беспокоиться о том, как задача решается, что именно происходит в фоновом режиме.
Повседневные объекты, которые мы используем, имеют абстракции, применяемые на разных уровнях. Одним из примеров объектно-ориентированного программирования является применение торможения в автомобиле. Эта система абстрактна: автолюбителю достаточно нажать на педаль, чтобы транспортное средство замедлило скорость и остановилось. Внесение изменений в систему ускорения не влияет на тормозную систему, так как они независимы. Водителю не нужно разбираться во внутренней работе тормозов. От него требуется только вовремя нажать на педаль. При этом тормоз (и дисковый, и барабанный) сработает, а машина замедлит скорость.
Инкапсуляция
Эта концепция тесно связана с абстракцией. Инкапсуляция — это раскрытие решения проблемы, не требующее от пользователя полного понимания ее предметной области. Она связывает данные и поведение в единое целое и не позволяет клиенту или пользователю модуля узнать о внутреннем представлении, в котором реализовано поведение абстракции.
Данные недоступны напрямую. Доступ к ним осуществляется через определенные функции. Скрытие внутренних элементов объекта защищает его целостность, не давая пользователям переводить внутренние данные компонента в недопустимое или несовместимое состояние.
Наследование
Это механизм повторного использования кода, который может помочь уменьшить его дублирование. Данная концепция является мощной функцией объектно-ориентированных языков программирования. Она помогает организовать классы в иерархию, позволяя им наследовать атрибуты и поведение от компонентов, стоящих выше.
Пример наследования: попугай — это птица, российский рубль – это вид валюты. Однако фраза «банк — это банковский счет» не верна. Эта связь очевидна, когда требуется описать какую-то сущность в данной постановке задачи. С помощью наследования можно определить общую реализацию ООП и его поведение, а затем для специализированных классов переопределить или изменить эти показатели на нечто более конкретное. Наследование не работает задом наперед. Исходник (так называемый родитель) не будет иметь свойств производного (дочернего класса).
Важно отметить, что при попытке смоделировать решение не стоит добавлять несколько уровней наследования. Нужно попытаться определить общие атрибуты и поведение в объектах, которые смоделированы. Далее на основе этого можно продолжить рефакторинг кода, определяющего подходящий родительский класс. Общая реализация может быть перемещена в него.
Полиморфизм
Эта концепция позволяет расширять компьютерные системы за счет создания новых специализированных объектов. Одновременно она дает возможность текущей версии взаимодействовать с новой, не обращая внимания на ее конкретные свойства.
Например, если стоит задача написать сообщение на листе бумаги, можно использовать ручку, карандаш, маркер или перо. Достаточно того, чтобы инструмент мог уместиться в руке и имел возможность оставлять след при соприкосновении с бумагой. Получается, что определенные действия человека делают надпись на листе, а какой при этом используется инструмент, это не столь важно для передачи информации.
Другим примером полиморфизма в системе объектно-ориентированного программирования являются самолет и космический челнок, которые можно назвать летающими объектами. Как именно они перемещаются в пространстве? Разумеется, в их работе есть большая разница. То есть способы реализации их движения неодинаковые. Однако с точки зрения зрителя оба объекта летят.
Наследование является одним из способов достижения полиморфизма, когда поведение, определенное в унаследованном классе, может быть переопределено путем написания пользовательской реализации метода. Это называется переопределением (полиморфизмом времени компиляции).
Существует еще одна форма полиморфизма, называемая перегрузкой, при которой наследование не учитывается. Имя метода будет таким же, но аргументы в методе разные.
Особенности понятий «класс» и «объект»
Чтобы начать работать с объектно-ориентированным программированием, нам нужно разобраться, что такое класс ООП и объект. Важно понимать разницу между ними. Класс — это план для создания объекта. Он определяет атрибуты и поведение. Это похоже на инженерный чертеж дома. Объект является экземпляром класса. Вот такая между ними разница. В примере ниже показано, каким образом объявляются класс «TForml» и переменная «Forml» на языке программирования Delphi:
Если мы хотим смоделировать в нашей программе, например, автомобиль, то должны определить его атрибуты: модель, топливо, марку, цвет, его поведение, а также так называемые методы: запуск двигателя, торможение, ускорение и так далее. Хорошо видно, что указанные показатели характерны не только для одной марки или модели транспортного средства.
При объектно-ориентированном подходе мы пытаемся обобщить наш объект (машину), утверждая, что тот, который мы собираемся смоделировать в нашей программе, будет иметь некоторое количество атрибутов и методов. Могут быть и другие показатели и характеристики транспортного средства, но нам достаточно перечисленных, чтобы понять, как работает класс в ООП.
Когда мы используем эти данные, мы создаем автомобиль с конкретными параметрами. Программируя один и тот же объект (машину), мы можем взять разные характеристики, как показано в таблице ниже:
Таким образом объектно-ориентированное программирование позволяет легко моделировать поведение сложной системы реального мира. С ООП данные и функции (атрибуты и методы) объединяются в объекте. Это предотвращает необходимость в каких-либо общих или глобальных данных с ООП. Такой подход является основным отличием объектно-ориентированного и процедурного подходов.
Классы ООП состоят из элементов различных типов:
- Поля данных: хранят состояние класса с помощью переменных и структур.
- Методы: подпрограммы для манипулирования указанными данными.
- Некоторые языки допускают третий тип — свойства. Это что-то среднее между первыми двумя.
Методы
Поведение класса или его экземпляров определяется с помощью методов. Это подпрограммы с возможностью оперировать объектами. Данные операции могут изменить состояние объекта или просто предоставить способы доступа к нему.
Существует множество методов. Их поддержка зависит от языка. Одни создаются и вызываются кодом программиста, другие (специальные, такие как конструкторы, деструкторы и операторы преобразования) создаются и вызываются сгенерированным компилятором кодом. Язык может позволить программисту определять эти специальные методы.
Интерфейс
Это определение группы абстрактных действий. Он выясняет, какое поведение должен демонстрировать определенный объект без указания того, как оно должно быть реализовано.
Объект может иметь несколько ролей, а пользователи имеют возможность использовать его с разных точек зрения. Например, объект типа «человек» может иметь роли:
- Солдата (с поведением «стреляй в противника»).
- Мужа (с поведением «люби свою жену»).
- Налогоплательщика (с поведением «плати налоги») и так далее.
Однако каждый объект реализует свое поведение по-своему: Миша платит налоги вовремя, Андрей с просрочкой, а Петр вообще этого не делает. То же можно сказать о каждом объекте и других ролях.
Появляется вопрос, почему базовый класс всех объектов не является интерфейсом. Причина в том, что в таком случае каждый класс должен будет реализовывать небольшую, но очень важную группу методов, что займет ненужное количество времени. Оказывается, что не всем классам нужна конкретная реализация — общей по умолчанию в большинстве случаев достаточно. Нет необходимости переопределять какие-либо методы, но если ситуация требует этого, то возможно реализовать их переопределение.
Хорошим примером являются кнопки на передней панели телевизора. Можно сказать, что они — это интерфейс между пользователем и электропроводкой на другой стороне корпуса прибора. Человек нажимает кнопку питания для включения и выключения электроприбора. В этом примере конкретный телевизор является экземпляром, каждый метод представлен кнопкой, а все вместе они составляют интерфейс. В своей наиболее распространенной форме он представляет собой спецификацию группы связанных методов без их реализации.
Конструктор
Этот критерий отвечает за подготовку объекта к действию, например, за установку начальных значений для всех его данных и их элементов. Хотя он играет особую роль, конструктор — это просто еще одна функция, с помощью которой можно передавать информацию через список аргументов. Их можно использовать для его инициализации. Имя функции конструктора и класса одинаковые.
Следующий пример объясняет концепцию конструктора класса на C++ (распространенном языке программирования):
Когда приведенный выше код компилируется и выполняется, он дает следующий результат:
Length of line: 6
Деструктор
Это специальная функция класса, которая уничтожает объект, как только заканчивается область его действия. Деструктор автоматически вызывается компилятором, когда объект выходит из области видимости.
Синтаксис для деструктора такой же, как и для конструктора, однако имя класса используется в данном случае для него со знаком тильды «
» в качестве префикса.
Следующий пример на языке C++ объясняет понятие деструктора:
Когда приведенный выше код скомпилирован и выполнен, он даст следующий результат:
Length of line: 6
В чем заключаются достоинства классов
Преимущества организации программного обеспечения в классы объектов делятся на три категории:
- Быстрое развитие.
- Простота обслуживания.
- Повторное использование кода и дизайна.
Классы и ООП в целом способствуют быстрой разработке, поскольку они уменьшают смысловой разрыв между кодом и пользователями. Это по достоинству оценили многие программисты. Благодаря этой системе аналитики могут общаться как с разработчиками, так и с пользователями, используя один и тот же словарь, говоря об учетных записях, клиентах, счетах и так далее.
Классы объектов часто способствуют быстрой разработке, поскольку большинство объектно-ориентированных сред имеют мощные средства отладки и тестирования. Экземпляры классов могут быть проверены во время выполнения, чтобы убедиться, что система работает должным образом. Кроме того, вместо получения дампов памяти ядра большинство объектно-ориентированных сред интерпретируют возможности отладки. В результате разработчики могут точно проанализировать, где в программе произошла ошибка, и увидеть, какие методы, аргументы и значения были использованы.