Все языки OOP, включая С++, основаны на трёх основополагающих концепциях, называемых инкапсуляцией, полиморфизмом и наследованием. Рассмотрим эти концепции.

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

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

Внутри объекта коды и данные могут быть закрытыми (private). Закрытые коды или данные доступны только для других частей этого объекта. Таким образом, закрытые коды и данные недоступны для тех частей программы, которые существуют вне объекта. Если коды и данные являются открытыми, то, несмотря на то, что они заданы внутри объекта, они доступны и для других частей программы. Характерной является ситуация, когда открытая часть объекта используется для того, чтобы обеспечить контролируемый интерфейс закрытых элементов объекта.

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

2. Полиморфизм

Полиморфизм (polymorphism) (от греческого polymorphos) — это свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Целью полиморфизма, применительно к объектно-ориентированному программированию, является использование одного имени для задания общих для класса действий. Выполнение каждого конкретного действия будет определяться типом данных. Например для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует трёх различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В С++ каждая из этих функций может быть названа abs(). Тип данных, который используется при вызове функции, определяет, какая конкретная версия функции действительно выполняется. В С++ можно использовать одно имя функции для множества различных действий. Это называется перегрузкой функций (function overloading).

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

Полиморфизм может применяться также и к операторам. Фактически во всех языках программирования ограниченно применяется полиморфизм, например, в арифметических операторах. Так, в Си, символ + используется для складывания целых, длинных целых, символьных переменных и чисел с плавающей точкой. В этом случае компилятор автоматически определяет, какой тип арифметики требуется. В С++ вы можете применить эту концепцию и к другим, заданным вами, типам данных. Такой тип полиморфизма называется перегрузкой операторов (operator overloading).

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

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

Наследование (inheritance) — это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него. Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации. Например, подумайте об описании жилого дома. Дом — это часть общего класса, называемого строением. С другой стороны, строение — это часть более общего класса — конструкции, который является частью ещё более общего класса объектов, который можно назвать созданием рук человека. В каждом случае порождённый класс наследует все, связанные с родителем, качества и добавляет к ним свои собственные определяющие характеристики. Без использования иерархии классов, для каждого объекта пришлось бы задать все характеристики, которые бы исчерпывающи его определяли. Однако при использовании наследования можно описать объект путём определения того общего класса (или классов), к которому он относится, с теми специальными чертами, которые делают объект уникальным. Наследование играет очень важную роль в OOP.

Инкапсуляция (англ. encapsulation , от лат. in capsula ) — в информатике размещение в одном компоненте данных и методов, которые с ними работают. Также может означать скрытие внутренней реализации от других компонентов. Например, доступ к скрытой переменной может предоставляться не напрямую, а с помощью методов для чтения (геттер) и изменения (сеттер) её значения.

Инкапсуляция зачастую рассматривается как понятие, присущее исключительно объектно-ориентированному программированию (ООП), но в действительности обширно встречается и в других (см. подтипизация на записях и полиморфизм записей и вариантов). В ООП инкапсуляция тесно связана с принципом абстракции данных (не путать с абстрактными типами данных, реализации которых предоставляют возможность инкапсуляции, но имеют иную природу). Это, в частности, приводит к другому распространённому заблуждению — рассмотрению инкапсуляции неотрывно от сокрытия. В частности, в сообществе С++ или Java принято рассматривать инкапсуляцию без сокрытия как неполноценную. Однако, некоторые языки (например, Smalltalk, Python) реализуют инкапсуляцию в полной мере, но не предусматривают возможности скрытия в принципе. Другие (Standard ML, OCaml) жёстко разделяют эти понятия как ортогональные и предоставляют их в семантически различном виде (см. сокрытие в языке модулей ML).

Содержание

Подробности [ править | править код ]

В общем случае в разных языках программирования термин «инкапсуляция» относится к одной или обеим одновременно следующим нотациям:

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

Слово "инкапсуляция" происходит от латинского in capsula — "размещение в оболочке". Таким образом, инкапсуляцию можно интуитивно понимать как изоляцию, закрытие чего-либо инородного с целью исключения влияния на окружающее, обеспечение доступности главного, выделение основного содержания путём помещения всего мешающего, второстепенного в некую условную капсулу (чёрный ящик).

# Темы занятия

  • Основные понятия и принципы ООП.
  • Инкапсуляция.
  • Классы, поля и методы.
  • Модификаторы доступа public и private .
  • Конструкторы и создание объектов.
  • Статические члены класса и константы.
  • Вложенные типы.

# Теоретические сведения

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

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

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

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

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

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

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

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

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

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

# Ссылки по теме

# Модификаторы доступа членов класса

Модификаторы доступа членов класса:

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

private — определяет закрытые члены класса, которые доступны только в классе, в котором они определены.

# Ссылки по теме

# 1.1. Тип точки

  1. Создайте тип точки Point .
  2. Определите модификаторы доступа членов классов.
  3. Продемонстрируйте работу с типом точки.

Создайте следующие поля:

ИмяТипДоступОписание
xfloatЧтениеАбсцисса точки.
yfloatЧтениеОрдината точки.
formatconst stringШаблон представления точки в виде строки.

# Конструкторы

Создайте следующие конструкторы:

СигнатураОписание
Point(float x, float y)Создаёт точку с координатами x и y .
Point(Point)Создаёт точку, копируя данные из другой точки.

# Методы

Создайте следующие методы:

СигнатураВозвр. типОписание
copy()PointВозвращает копию точки.
equals(Point)boolВозвращает результат сравнения точки с другой точкой.
static equals(Point first, Point second)boolВозвращает результат сравнения точки first с точкой second .
toString()stringВозвращает строку* с информацией о координатах точки**.

** Округлите координаты до двух знаков после запятой.

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

По возможности используйте перегрузку операторов

и переопределяйте стандартные методы.

Если в классе присутствуют поля, доступные только для чтения, или только для записи, то такие поля рекомендуется делать закрытыми или защищёнными, и реализовать соответствующие методы доступа.

# 1.2. Тип вектора

  1. Создайте тип вектора Vector .
  2. Определите модификаторы доступа членов классов.
  3. Продемонстрируйте работу с типом вектора.

Создайте следующие поля:

ИмяТип*ДоступОписание
startPointЧтениеТочка начала вектора.
endPointЧтениеТочка конца вектора.
formatconst stringШаблон представления вектора в виде строки.

* Используйте тип точки Point , созданный в предыдущем задании.

# Конструкторы

Создайте следующие конструкторы:

СигнатураОписание
Vector()Создаёт нулевой вектор.
Vector(Point)Создаёт радиус-вектор.
Vector(Point start, Point end)Создаёт вектор с точкой начала start и точкой конца end .
Vector(Vector)Создаёт вектор, копируя данные из другого вектора.

# Методы

Создайте следующие методы:

СигнатураВозвр. типОписание
add(Vector)VectorВозвращает сумму вектора и другого вектора.
static add(Vector first, Vector second)VectorВозвращает сумму вектора first с вектором second .
copy()VectorВозвращает копию вектора.
equals(Vector)boolВозвращает результат сравнения вектора с другим вектором.
static equals(Vector first, Vector second)boolВозвращает результат сравнения вектора first с вектором second .
getNorm()floatВозвращает модуль (длину) вектора.
mul(Vector)floatВозвращает скалярное произведение вектора и другого вектора.
static mul(Vector first, Vector second)floatВозвращает скалярное произведение вектора first с вектором second .
mul(float)VectorВозвращает произведение вектора с числом.
static mul(Vector vector, float number)VectorВозвращает произведение вектора vector с числом number .
sub(Vector)VectorВозвращает разность вектора с другим вектором.
static sub(Vector first, Vector second)VectorВозвращает разность вектора first с вектором second .
toString()stringВозвращает строку* с информацией о координатах вектора.

# 1.3. Тип человека

  1. Создайте тип человека Human .
  2. Создайте тип пола Gender человека, вложенный в тип человека.
  3. Определите модификаторы доступа членов классов.
  4. Продемонстрируйте работу с типом человека.

# Тип пола человека

Создайте следующие поля:

ИмяТип*ДоступОписание
MALEconst GenderЧтениеЗначение, представляющее мужской пол.
FEMALEconst GenderЧтениеЗначение, представляющее женский пол.

* Тип пола человека Gender реализуйте по возможности в виде перечисления

# Методы

Создайте следующие методы:

СигнатураВозвр. типОписание
static toString(Gender)stringВозвращает строковое представление значения типа пола человека.

# Тип человека

Создайте следующие поля:

ИмяТипДоступ*Описание
namestringЧтение ЗаписьИмя человека.
surnamestringЧтение ЗаписьФамилия человека.
genderGenderЧтение ЗаписьПол человека.
ageintЧтение ЗаписьВозраст человека в годах.
heightfloatЧтение ЗаписьРост человека в сантиметрах.
weightfloatЧтение ЗаписьВес человека в килограммах.
formatconst stringШаблон представления человека в виде строки.

* Все операции с полями, доступными на чтение и запись, должны происходить только через методы класса.

# Конструкторы

Создайте следующие конструкторы:

СигнатураОписание
Human(string name, string surname)Создаёт человека с именем name и фамилией surname (пол неопределён, числовые поля равны 0 ).
Human(string name, string surname, Gender gender)Создаёт человека с именем name , фамилией surname и полом gender (числовые поля равны 0 ).
Human(string name, string surname, Gender gender, int age, float height, float weight)Создаёт человека с именем name , фамилией surname , полом gender , возрастом age , ростом height и весом weight .
Human(Human)Создаёт человека, копируя данные из другого человека.

# Методы

Создайте следующие методы:

СигнатураВозвр. типОписание
copy()HumanВозвращает копию человека.
equals(Human)boolВозвращает результат сравнения человека с другим человеком по имени и фамилии.
static equals(Human first, Human second)boolВозвращает результат сравнения человека first с человеком second по имени и фамилии.
toString()stringВозвращает строку* с информацией о человеке**.

** Рост и вес округлите до одного знака после запятой.

Количество конструкторов у класса можно сократить с помощью аргументов по умолчанию.