Ответы на билеты (билет 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); */

};


Параметры для конструктора базового класса задаются в определении конструктора производного класса. В этом смысле базовый класс выступает как класс, являющийся членом производного класса:


Случайные файлы

Файл
159705.rtf
81356.rtf
011-0036.doc
26558-1.rtf
115580.rtf




Чтобы не видеть здесь видео-рекламу достаточно стать зарегистрированным пользователем.
Чтобы не видеть никакую рекламу на сайте, нужно стать VIP-пользователем.
Это можно сделать совершенно бесплатно. Читайте подробности тут.