Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция_01_Обзор объектно-ориентированного прогр...doc
Скачиваний:
5
Добавлен:
10.11.2019
Размер:
88.58 Кб
Скачать

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

Слово полиморфизм имеет греческое происхождение и переводится как "имеющий много форм".

Полиморфизм – это свойство, которое позволяет одно и то же имя использовать для решения нескольких технически разных задач.

Полиморфизм дает возможность создавать множественные определения для операций и функций. Какое именно определение будет использоваться, зависит от контекста программы. Вы уже знакомы с одной из разновидностей полиморфизма в языке C++ – перегрузкой функций. Программирование с классами предоставляет еще две возможности: перегрузку операций и использование так называемых виртуальных методов. Перегрузка операций позволяет применять для собственных классов те же операции, которые используются для встроенных типов C++. Виртуальные методы обеспечивают возможность выбрать на этапе выполнения нужный метод среди одноименных методов базового и производного классов.

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

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

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

Представьте, что нужно открыть замок и у нас есть связка ключей. И вот мы стоим перед замком и пытаемся его открыть. Мы имеем связку ключей, у каждого из которых есть какие-то параметры (форма, размер и т.д.). Для того, чтобы открыть дверь мы перибираем один ключ за другим пока не найдем подходящий. Т.е. когда шаблон замка совпадает с шаблоном параметров ключа, замок открывается. Аналогично работает компилятор при наличие нескольких функций. Он последовательно проверяет шаблоны функций с одним и тем же именем пока не найдет подходящий.

Класс

Класс (class) – это группа данных и методов (функций) для работы с этими данными. Это шаблон. Объекты с одинаковыми свойствами, то есть с одинаковыми наборами переменных состояния и методов, образуют класс.

Класс – это механизм для создания новых типов.

Мы уже говорили о классах и его отличиях от объекта, когда рассматривали понятие объекта.

Примерная структура класса (Она не привязанная к какому-либо языку ООП).

class имя_класса [от кого унаследован]

{

private:

. . . . . . .

public:

. . . . . . .

protected:

. . . . . . .

}

Понятно, что класс должен иметь уникальное имя. Если он наследован из другого, то надо указать имя родительского(ких) класса(ов). Обычно у класса бывают три раздела: private, public, protected. Спецификатор private часто опускается и, если не объявлено начало ни одного из других разделов описания класса, считается, что данные относятся к разделу private.

Private (частный) раздел описания класса обычно находится вначале описания класса и содержит данные, доступ к которым закрыт из внешнего мира. Это и есть та самая "строго охраняемая" зона класса, доступ к которой можно получить только из методов самого класса. Она скрыта от внешнего мира глухой непробиваемой стеной и доступ к данным раздела private обеспечивается только с помощью, специально описанных в других разделах, методов. Скрытые в этом разделе данные также не доступны для всех производных классов.

Если бы все данные, описанные в базовом (родительском) классе, были доступны для производных классов, то можно было бы просто создать суперкласс, а затем из производных классов получать свободный доступ ко все данным родительского класса. В то же время это перечеркнуло бы все наши старания по скрытию и защите данных. По этой причине, производные (наследуемые) классы автоматически не получают доступ к данным родительского класса (раздел private). Но бывают такие случаи, когда необходимо автоматически наследовать некоторые данные из родительского класса так, чтобы они вели себя так, как будто они описаны в производном классе. Именно для этих целей и существует раздел protected (защищенный) описания класса.

Protected (защищенный) – раздел описания класса содержит данные и методы, доступ к которым закрыт из внешней среды, но они напрямую доступны производным классам.

Таким образом, раздел protected используется для описания данных и методов, которые будут доступны только из производных классов. А в производных классах эти данные и методы воспринимаются, как если бы они были описаны в самом производном классе.

Название раздела public для англоязычной публики говорит само за себя. Переводится как публичный, я бы сказал, открытый раздел. Методы, описанные в разделе public доступны в пределах области видимости объекта и для производных классов. Таким образом, можно получить свободный доступ к методам, описанным в разделе public, из любого места программы (объект должен быть виден) и из любого производного класса. Методы, входящие в этот раздел, образуют интерфейс класса, с помощью которого и осуществляется взаимодействие экземпляра класса с внешним миром. Это единственный раздел, доступ к которому из внешней среды никак не ограничен.

Конструкторы и деструкторы.

Если Вы хотя бы в какой-то мере пытались разобраться в работе ООП, Вы обязательно натыкались на такие понятия, как Конструкторы и Деструкторы. Впрочем эти структуры могут иметь и другое название, к примеру, как в Visual Basic. Но это не имеет принципиального значения. Так что же означают эти понятия ? Я рассмотрю общие правила применения конструкторов и деструкторов в С++.

К сожалению, а может быть и к счастью, понятия в ООП тесно взаимосвязаны между собой. Невозможно объяснить одно понятие отдельно от других. В ООП есть понятие области видимости объекта, переменной. Это понятие я возможно затрону по подробнее, но не сейчас. Переводя это понятие на нормальный человечекий язык - это время жизни чего(или кого)-либо. К примеру, человек зачат (извиняюсь за такие интимные подробности), рождается, живет, учится, работает, что-то делает и, к сожалению, умирает, его тело превращается в прах. Аналогично и с объектами. Проводя дальнейшую аналогию, конструктор работает на отрезке времени с момента зачатия до момента рождения. На этом этапе происходит формирование скелета объекта (инициализация). Также можно провести аналогию с таким детским конструктором как Лего. У вас есть кубики или части определенной конфигурации и из них собираете какую-то конструкцию (фигуру, замок и т.д.). Таким образом, конструктор отвечает за начальное формирование(инициализацию) объекта на этапе его создания.

Очень часто конструктор заимствуется из родительского класса, но далеко не всегда.

В языке С++ конструктор имеет тоже самое имя, что и имя класса и не может иметь какой-либо определенный возвращаемый тип, поскольку имеет заранее определенный возвращаемый тип - указатель на инициализируемый объект.

Следует отметить, что функция конструктора запускается на этапе описания (декларирования) объекта. Т.е. декларирование объекта MyObject класса CMyObject следующей строкой

CMyObject MyObject;

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

Для тех, кто собирается работать с языком С++ на заметку: Если декларирование объекта произведено до выполнения основного модуля, то функция конструктора будет выполнена до выполнения этого модуля.

Продолжая аналогию с челоческой жизнью, Деструктор работает на отрезке времени, когда человек уже умер, но еще не превратился в прах. Т.е. вернуть, к сожалению, его уже нельзя, но сделать какой-то завершающий аккорд еще можно. Чаще всего этот этап используется для "зализывания ран" - корректного освобождения блоков памяти, выделенных при работе с этим объектом. Дело в том, что при "умирании" объекта, "умирают" и ссылки на все блоки памяти, которые были выделены объекту в процессе работы. Если мы не освободим выделенные объекту блоки памяти, то никто и не подумает их освобождать. В результате получится, что мы храним данные, которые нам уже абсолютно не нужны и мы даже не имеем к ним доступа ! В больших программах это может привести не только к краху самой программы, но и к замедлению работы или даже зависанию операционной системы. Применение деструктора в этом случае помогает избежать утечек памяти(memory leaks).

Итак, когда объект уже "представился" и готов уйти в небытие, автоматически вызывается деструктор, естесственно, если он существует.

В языке С++ Деструктор имеет тоже имя, что и имя класса с предшествующей ему тильдой. Деструктор не имеет никакого возвращаемого типа.

Ниже приведен пример класса с Конструктором и Деструктором в С++. Этот код не имеет никакого реального смысла, но наглядно показывает как можно использовать конструктор и деструктор.

сlass CMyClass

{

public:

CMyClass(); // Конструктор класса CMyClass

~CMyClass(); // Деструктор класса CMyClass

private:

int MyInt; // переменная типа integer (целое число)

int *point; // переменная типа указатель на integer (целое число)

};

CMyClass::CMyClass() // Конструктор

{

MyInt=10; // На этапе инициализации объекта класса CMyClass присваиваем

// переменной этого объекта MyInt значение 10

point = new int; // Выделяем блок памяти под целое число, на которое

// будет указывать указатель

*point = 20; // Сохраняем в этот выделенный блок памяти число 20

}

CMyClass::~CMyClass() // Деструктор

{

MyInt=0; // Объект класса CMyClass уже фактически прекратил существование,

// но мы присваиваем переменной класса MyInt значение 0

delete point; // Используем указатель на число для того, чтобы освободить

// блок памяти, выделенный под это число.

// Если мы этого здесь не сделаем, никто за нас это не сделает

}

И последнее, что хотелось бы отметить, реализация конструкторов и деструкторов в конкретных языках может отличаться или могут существовать какие-либо специфические особенности их реализации. Я сознательно коснулся только общих принципов их работы. Для более полного обзора данных структур конкретного языка программирования лучше всего обращается к описанию его разработчика. К примеру, в языке С++ существует ряд других, не указанных мной, особенностей реализации и автоматического генерирования (при их отстутствии) конструкторов.

9