§ 13. Объекты
Наследование, инкапсуляция и полиморфизм
01 C++ — это язык, который сочетает в себе сразу несколько подходов к программирования, и основным подходом считается объектно-ориентированный. Этот подход описывает предметную область вашей задачи, используя объекты и их методы. Объект — это абстрактное понятие, которое включает в себя объекты и процессы (физические, математические и другие), а метод — это абстрактный функционал, связанный с объектом.
02 Допустим, вы решили написать программу, которая моделирует качку судна. В этой программе у вас непременно будет объект судно
, параметрами которого будут углы поворота относительно каждой из осей координат, масса, геометрия и др., а одним из методов этого объекта будет повернуть судно на определенный угол вокруг заданной оси
, в котором угол и ось будут параметрами. Это называет инкапсуляцией: объект судно
скрывает в себе параметры, которые изменяются посредством вызова методов этого объекта и никак иначе.
03 Затем, вы решили написать программу, которая рисует на экране простые геометрические фигуры: треугольник, окружность, прямоугольник и т.п. В этой программе у вас непременно будут объекты, которые соответствуют каждой фигуре: объект треугольник
с координатами каждой точки в качестве параметров, объект окружность
с координатой центра и радиусом и объект прямоугольник
с координатой левого верхнего и правого нижнего угла. У каждого из этих объектов будет метод нарисовать
. Этот метод вызывается одинаково для каждого объекта, но реализация этого метода уникальна для каждого объекта. Это называется полиморфизмом — объекты разные, а функционал один и тот же и предоставляется через один и тот же интерфейс.
04 Наконец, вы решили написать программу, которая моделирует движение трехмерных объектов (компьютерную игру, например). Тогда в вашей программе обязательно появится объект, который является базовым для всех объектов, отображаемых на экране. Этот объект будет содержать координаты и какие-нибудь другие поля в качестве параметров. Все остальные объекты буду создаваться на его основе, наследуя все его параметры и методы. Это так и называется — наследование.
05 Инкапсуляция, наследование и полиморфизм являются основой объектно-ориентированного подхода к разработке программ. Такие программы состоят из объектов и методов, внутри которых вызываются методы других объектов, в которые еще одни объекты передаются в качестве параметров. Преимуществами данного подхода являются
- простота (все объекты взяты из предметной области задачи),
- возможность совместной разработки (изменения, которые необходимо внести в код для добавления новых возможностей, как правило, затрагивают небольшое количество объектов).
Классы
06 В С++ для создания объекта сначала надо определить его класс. Это делается с помощью ключевого слова class
. Класс является описанием общедоступного интерфейса объекта и содержит в себе список полей, список методов и список типов. Для каждого элемента класса определяется уровень доступа: private
— элемент доступен только внутри класса, protected
— элемент доступен внутри класса и во всех классах-наследниках, public
— элемент доступен из любого контекста. Как правило, все поля класса делают доступными только внутри класса, а для доступа к ним используют общедоступные методы. Это выгодно, если надо измененить реализацию класса: поля можно поменять без изменения методов. Скрытые методы и типы используют для сокрытия внутренней реализации класса. Уровни доступа работают только на этапе компиляции, во время запуска программы они ни на что не влияют.
// файл ship.hh /* asdasd */ class Ship { private: float angleX = 0; float angleY = 0; float angleZ = 0; float mass = 0; public: Ship(float mass); // конструктор ~Ship(); // деструктор void rotate(float delta, int axis); // метод (объявление) inline float getMass() const { return mass; } // метод (объявление и определение) };
Ship
с полями, методами, конструктором и деструктором. Файл ship.hh.07 Для создания объекта используется тот же синтаксис, что и для объявления и определения переменных, но с указанием класса в качестве типа переменной. Для объектов объявление и определения совмещено, и при объявлении сразу вызывается конструктор соответствующего класса, а когда программа выходит из блока кода, в котором был объявлен объект, то вызывается деструктор класса. Конструктор и деструктор являются методами класса, вызов которых происходит автоматически. Привязка вызова этих методов к синтаксической структуре программы является главным отличием C++ от других языков.
int main() { Ship ship(123); // вызов конструктора Ship std::cout << "Ship mass: " << ship.getMass() << '\n'; return 0; // вызов деструктора Ship }
Ship
.08 Конструкторы используются для инициализации полей объекта. Это можно сделать, передав в конструктор аргументы, и, написав в теле конструктора код, вычисляющий значения полей. Для полей, которые не были проинициализированы, вызывается конструктор по умолчанию (конструктор без аргументов), а для примитивных типов конструктор не вызывается, и такие поля имеют произвольные значения.
09 Деструкторы используются для освобождения ресурсов, которые были выделены в конструкторе. Обычно, это оперативная память, но может быть и любой другой системный ресурс, например, файловый дескриптор. Для всех полей деструкторы вызываются автоматически.
10 Методы класса можно объявить — то есть указать имя, типы аргументов и тип возвращаемого значения, — а можно определить — то есть написать тело метода. Для простых методов объявление и определение обычно совмещают, то есть сразу после объявления пишут тело метода. Это выгодно с точки зрения производительности, поскольку тела таких методов вставляются в место вызова оптимизатором (при условии, что они достаточно небольшие), и экономятся инструкции необходимые для вызова метода. Для сложных методов объявление и определения пишутся отдельно: объявление пишут в заголовочном файле, а определение — в основном файле. Сами файлы называют по имени класса. Если вы хотите, чтобы совместное объявление и определение работало корректно, то необходимо добавить ключевое слово inline
к нему. Если метод не изменяет поля объекта, то добавляют ключевое слово const
к его определению.
// файл ship.cc #include "ship.hh" Ship::Ship(float m): mass(m) { // конструктор } Ship::~Ship() { // деструктор } void Ship::rotate(float delta, int axis) { // метод }
Ship
с полями, методами, конструктором и деструктором. Файл ship.cc.Задания
Point1 балл
11 Создайте класс Point
, который представляет собой точку в трехмерном пространстве. Напишите программу, в которой создаются объекты этого класса и выводятся на экран их координаты. Нужна ли инкапсуляция для этого класса?
Rectangle1 балл
12 Создайте класс Rectangle
, который представляет собой прямоугольник в двухмерном пространстве. Напишите программу, в которой создаются объекты этого класса и выводятся на экран их параметры. Нужна ли инкапсуляция для этого класса? Какие наборы полей можно использовать для описания прямоугольника?
Triangle1 балл
13 Создайте класс Triangle
, который представляет собой треугольник в трехмерном пространстве. В классе должно быть не больше трех полей. Напишите программу, в которой создаются объекты этого класса и выводятся на экран их параметры.
Ship2 балла
14 Создайте класс Ship
, который представляет собой судно в трехмерном пространстве. Параметрами судна являются масса и углы поворота по каждой из осей. Методом класса является метод rotate
, который поворачивает судно на указанный угол вокруг указанной оси. Напишите объявление класса в файле ship.hh, определение методов — в файле ship.cc, а функцию main
— в файле main.cc. Как можно изменить поля, так чтобы упростить реализацию метода rotate
?
Видео
- 00:00 Наследование, инкапсуляция и полиморфизм.
- 07:10 Инкапсуляция.
- 21:30 Заголовчные файлы и файлы с кодом класса.
- 24:33 Ключевое слово
inline
. - 28:49 Ключевое слово
const
. - 30:00 Ключевое слово
noexcept
. - 33:15 Вопрос про область видимости переменных.
- 35:00 Вопрос про приватный конструктор.
- 35:52 Наследование и полиморфизм.
- 52:10 Вопрос про чисту виртуальную функцию.