билет 20 (Ответы на билеты)
Описание файла
Файл "билет 20" внутри архива находится в папке "Bilety_s_otvetami-progr". Документ из архива "Ответы на билеты", который расположен в категории "". Всё это находится в предмете "программирование" из 3 семестр, которые можно найти в файловом архиве МПУ. Не смотря на прямую связь этого архива с МПУ, его также можно найти и в других разделах. Архив можно найти в разделе "к экзамену/зачёту", в предмете "программирование" в общих файлах.
Онлайн просмотр документа "билет 20"
Текст из документа "билет 20"
Наследование — один из четырёх важнейших механизмов объектно-ориентированного программирования (наряду с абстракцией, инкапсуляцией и полиморфизмом), позволяющий описать новый класс на основе уже существующего (родительского), при этом свойства и функциональность родительского класса наследуются новым классом.
Другими словами, класс-наследник реализует спецификацию уже существующего класса (базовый класс). Это позволяет обращаться с объектами класса-наследника точно так же, как с объектами базового класса 1
Типы наследования
Простое наследование
Класс, от которого произошло наследование, называется базовым или родительским (англ. base class). Классы, которые произошли от базового, называются потомками, наследниками или производными классами (англ. derived class).
В некоторых языках используются абстрактные классы. Абстрактный класс — это класс, который описан в программе, имеет поля, функции, но не используется для создания объекта. Объекты создаются только на основе производных классов, наследованных от абстрактного. Например, абстрактным классом может быть базовый класс «сотрудник ВУЗа», от которого наследуются классы «аспирант», «профессор» и т.д. Т.к. производные классы имеют общие поля и функции (например, поле «год рождения»), то эти члены класса могут быть описаны в базовом классе. В программе создаются объекты на основе классов «аспирант», «профессор», но нет смысла создавать объект на основе класса «сотрудник вуза».
Множественное наследование
При множественном наследовании у класса может быть более одного предка. В этом случае класс наследует методы всех предков. Достоинства такого подхода в большей гибкости. Множественное наследование реализовано в C++. Из других языков, предоставляющих эту возможность, можно отметить Python. Множественное наследование поддерживается в языке UML.
Множественное наследование — потенциальный источник ошибок, которые могут возникнуть из-за наличия одинаковых имен методов в предках. В языках, которые позиционируются как наследники C++ (Java, C# и др.), от множественного наследования было решено отказаться в пользу интерфейсов.
Большинство современных объектно-ориентированных языков программирования (C#, Java, Delphi и др.) поддерживает возможность одновременно наследоваться от класса-предка и реализовать методы нескольких интерфейсов одним классом. Этот механизм позволяет во многом заменить множественное наследование — методы интерфейсов необходимо переопределять явно, что исключает ошибки при наследовании функциональности одинаковых методов различных классов-предков.
Наследование в языке C++
«Наследование» в C++:
class A{ //базовый класс
};
class B : public A{ //public наследование
}
class C : protected A{ //protected наследование
}
class Z : private A{ //private наследование
}
В C++ существует три типа наследования: public, protected, private. Спецификаторы доступа членов базового класса меняются в потомках следующим образом:
-
при public-наследовании все спецификаторы остаются без изменения.
-
при protected-наследовании все спецификаторы остаются без изменения, кроме спецификатора public, который меняется на спецификатор protected (то есть public-члены базового класса в потомках становятся protected).
-
при private-наследовании все спецификаторы меняются на private.
Одним из основных преимуществ public-наследования является то, что указатель на классы—наследники может быть неявно преобразован в указатель на базовый класс, то есть для примера выше, можно написать
A* a = new B;
Эта интересная особенность открывает возможность динамической идентификации типа.
2) Интерфе́йс (от лат. inter — между и лат. face — поверхность) — это семантическая и синтаксическая конструкция в коде программы, используемая для специфицирования услуг, предоставляемых классом или компонентом.
Интерфейс определяет границу взаимодействия между классами или компонентами, специфицируя определенную абстракцию, которую осуществляет реализующая сторона. В отличие от большинства других видов интерфейсов, интерфейс в ООП является строго формализованным элементом объектно-ориентированного языка и, в качестве семантической конструкции, широко используется кодом программы. К примеру, интерфейс «Cloneable» может описать абстракцию клонирования (создания точных копий) объектов, специфицировав метод «Clone». Тогда любой класс, способный создать свою копию, может задекларировать себя как Cloneable и предоставить метод Clone. Причем вызывающей стороне достаточно знать только описание интерфейса. Таким образом, интерфейсы позволяют рассоединить части программной системы в модули без взаимной зависимости кода.
С одной стороны, интерфейс — это контракт, который обязуется выполнить класс, реализующий его. Один класс может реализовать несколько интерфейсов одновременно.
С другой стороны, интерфейс — это тип данных, потому что его описание достаточно четко определяет свойства объектов, чтобы наравне с классом типизировать переменные.
Интерфейсы в C++
Роль интерфейсов в C++ выполняют абстрактные классы.
3) Конструктор — специальный метод класса в объектно-ориентированном программировании, служащий для инициализации объекта при его создании (например выделения памяти). В языках программирования С++ или Java конструктором класса называется функция, имеющая то же имя, что и сам класс, и не возвращающая никакого значения. Говоря более простым языком, конструктором называется тот метод класса, который вызывается автоматически при создании экземпляра класса.
Иногда используют более узкие термины: конструктор по умолчанию, конструктор копирования, конструктор преобразования.
Виды конструкторов
class Complex
{
double re,im;
public:
Complex(double i_re=0,double i_im=0):re(i_re),im(i_im){} //Конструктор по умолчанию
// (в данном случае является также и конструктором преобразования)
Complex(Complex& obj){re=obj.re;im=obj.im;} //Конструктор копирования
}
Конструктор по умолчанию
Конструктор не имеющий обязательных аргументов. Используется при создании массивов объектов, вызываясь для создания каждого экземпляра. В отсутствие явно заданного конструктора по умолчанию его код генерируется компилятором (что на исходном тексте, естественно, не отражается).
Конструктор копирования
Конструктор, аргументом которого является ссылка на объект того же класса. Эта особенность (необходимость передачи параметра именно по ссылке, а не по значению) вытекает из коллизии: при передаче объекта по значению (в частности для вызова конструктора) требутеся скопировать объект. Но для того чтобы скопировать объект необходимо вызвать конструктор копирования.
Наличие конструктора копирования становится необходимым, например, если для хранения данных объекта требуется дополнительно выделяемая память.
Если его не будет, то конструктором копирования (сгенерированным компилятором) будут скопированы указатели, адресующие данные прежнего объекта (без выделения новой памяти). Соответственно попытка изменения "копии" повредит оригинал, а вызов деструктора для одного из этих объектов при последующем использовании другого приведёт к обращению в область памяти, уже не принадлежащей программе.
Конструктор преобразования
Конструктор, имеющий произвольные аргументы (термин может быть применён в первом случае). Так, например, при вызове Complex a(1); конструктор из первого примера преобразовывает действительное число 1 в комплексное (1;0).
Виртуальный конструктор
Конструктор не бывает виртуальным в смысле виртуального метода — для того, чтобы механизм виртуальных методов работал, нужно запустить конструктор, который автоматически настроит таблицу виртуальных методов данного объекта.
«Виртуальными конструкторами» называют похожий, но другой механизм, присутствующий в некоторых языках — например, он есть в Delphi, но нет в Java. Этот механизм позволяет создать объект любого заранее неизвестного класса при двух условиях:
-
Этот класс является потомком некоего наперёд заданного класса (в данном примере это класс TVehicle)
-
На всём пути наследования от базового класса к создаваемому цепочка переопределения не обрывалась.
type
TVehicle = class
constructor Create; virtual;
end;
TAutomobile = class (TVehicle)
constructor Create; override;
end;
TMotorcycle = class (TVehicle)
constructor Create; override;
end;
TMoped = class (TMotorcycle) // обрываем цепочку переопределения - заводим новый Create
constructor Create(x : integer); reintroduce;
end;
В языке вводится так называемый классовый тип. Этот тип в качестве значения может принимать название любого класса, производного от TVehicle.
type
CVehicle = class of TVehicle;
Такой механизм позволяет создавать объекты любого заранее неизвестного класса, производного от TVehicle.
var
cv : CVehicle;
v : TVehicle;
cv := TAutomobile;
v := cv.Create;
Заметьте, что код
cv := TMoped;
v := cv.Create;
является некорректным — директива reintroduce разорвала цепочку переопределения виртуального метода, и в действительности для мопеда будет вызван конструктор TMotorcycle.Create.
Синтаксис
Имя конструктора должно совпадать с именем класса. Допускается использовать несколько конструкторов с одинаковым именем, но различными параметрами
class ClassWithConstructor {
private:
AnotherClass object;
public:
/* Инициализация внутреннего объекта с помощью конструктора */
ClassWithConstructor(float parameter): object(parameter) {}/* вызов метода AnotherClass(float); */
};
Параметры для конструктора базового класса задаются в определении конструктора производного класса. В этом смысле базовый класс выступает как класс, являющийся членом производного класса:
manager::manager(char* n, int l, int d)
: employee(n,d), level(l), group(0)
{
}
Конструктор базового класса employee::employee() может иметь такое определение:
employee::employee(char* n, int d)
: name(n), department(d)
{
next = list;
list = this;
}
Здесь list должен быть описан как статический член employee. Объекты классов создаются снизу вверх: вначале базовые, затем члены и, наконец, сами производные классы. Уничтожаются они в обратном порядке: сначала сами производные классы, затем члены, а затем базовые. Члены и базовые создаются в порядке описания их в классе, а уничтожаются они в обратном порядке.
Производные классы должны обычно определять конструктор копии и функцию operator=( )
ПОРЯДОК ВЫЗОВА КОНСТРУКТОРОВ
Порядок вызова конструкторов при создании объектов производных классов в С++ фиксирован - он идет от корневого базового класса к производным по дереву наследования. Прежде всего строится базовый класс, затем производный. Если базовый класс, в свою очередь, является про изводным, то процесс рекурсивно повторяется до тех пор, пока не будет достигнут корневой класс.ПОРЯДОК ВЫЗОВА ДЕСТРУКТОРОВ обратный к порядку вызова конструкторов.