c++ Базовый. Занятие 11

20
Модуль 3 : Основные понятия объектно-ориентированного программирования. Темы лекции : Полиморфизм. Практическое задание : Полиморфизм. Тренер: Игорь Шкулипа, к.т.н. C++ Базовый. Занятие 11

Upload: igor-shkulipa

Post on 12-Apr-2017

42 views

Category:

Education


1 download

TRANSCRIPT

Page 1: C++ Базовый. Занятие 11

Модуль 3: Основные понятия объектно-ориентированного программирования.

Темы лекции: Полиморфизм.

Практическое задание: Полиморфизм.

Тренер: Игорь Шкулипа, к.т.н.

C++ Базовый. Занятие 11

Page 2: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 2

Преобразование типов

В С++ существуют операторы преобразования типов:

⚫ const_cast < > ( )

⚫ static_cast < > ( )

⚫ reinterpret_cast < > ( )

⚫ dynamic_cast < > ( )

Page 3: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 3

const_cast

Оператор const_cast позволяет убрать или добавитьконстантность

const ClassA * constA = {/*инициализатор*/};

ClassA * A = const_cast<ClassA *>(constA);

const_cast не применим для тех объектов, которые объявленыкак const. В таком случае нельзя отменять константность, таккак будет undefined behaviour.

Page 4: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 4

reinterpret_cast

Оператор reinterpret_cast приводит друг к другу указатели,которые друг от друга не зависят, не меняя константности

ClassA * p = new ClassA();

double * d = reinterpret_cast<double*>(p);

Оператор reinterpret_cast является машинно-зависимым. Чтобыбезопасно использовать оператор reinterpret_cast, следуетхорошо понимать, как именно реализованы используемыетипы, а также то, как компилятор осуществляет приведение

Page 5: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 5

static_cast

Оператор static_cast выполняет преобразование междусвязанными значениями. Связанность проверяется на этапекомпиляции, поэтому и называется static.

//Класс Derived является наследником Base

Derived * der = ...;

Base * bas = static_cast<Base *>(der);

der = static_cast<Derived *>(bas);

Типы, к котрым применим static_cast:

⚫ числовые типы

⚫ классы, связанные наследованием

⚫ приведение к void*

Page 6: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 6

dynamic_cast

Безопасное приведение по иерархии наследования.

dynamic_cast<Derived *>(base_pointer)

Используется RTTI (Runtime Type Information), чтобы привестиодин указатель на объект класса к другому указателю наобъект класса.

Классы должны быть полиморфными, то есть в базовом класседолжна быть хотя бы одна виртуальная функция. Если этоусловие не соблюдено, ошибка возникнет на этапекомпиляции. Если приведение невозможно, то об этом станетясно только на этапе выполнения программы и будетвозвращен NULL.

Page 7: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 7

Полиморфизм

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

Использование полиморфизма достигается при присвоенииуказателю на базовый класс адреса производного класса спереопределенными методами.

Типы-наследники неявно приводимы к базовому классу.

Page 8: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 8

Примерclass Point

{

private: double _x, _y;

...

}

class Figure

{

protected: Point _center;

public: double GetArea(){return 0;};

}

class Circle: public Figure

{

private: double _radius;

...

public: double GetArea(){return 3.14*_radius*_radius;};

}

class Rectangle: public Figure

{

private: double _width, _height;

...

public: double GetArea(){return _width*_height;};

}

Figure

Circle Rectangle

Page 9: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 9

Результат 1

void main()

{

Circle circle(10);

Rectangle rectangle(10, 20);

cout << circle.GetArea() << "\n";

cout << rectangle.GetArea() <<

"\n";

return 0;

}

Результат:

>314>200

Page 10: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 10

Результат 2

void PrintArea(const Figure& figure)

{

cout << figure.GetArea() <<

"\n";

}

void main()

{

Circle circle(10);

Rectangle rectangle(10, 20);

PrintShapeArea(circle);

PrintShapeArea(rectangle);

return 0;

}

Результат:

>0>0

В данной ситуации при выборе вызываемыхметодов компилятор руководствуется типомссылки.

В этом случае происходит вызов методовкласса Shape, так как функция PrintAreaпринимает ссылку данного типа.

Page 11: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 11

Виртуальные методы

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

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

Виртуальные функции обозначаются в объявлении класса припомощи ключевого слова virtual.

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

Page 12: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 12

Примерclass Figure

{

protected: Point _center;

public:

virtual double GetArea(){return 0;};

}

class Circle: public Figure

{

private: double _radius;

...

public:

virtual double GetArea(){return 3.14*_radius*_radius;};

}

class Rectangle: public Figure

{

private: double _width, _height;

...

public:

virtual double GetArea(){return _width*_height;};

}

Page 13: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 13

Результат

void PrintArea(const Figure& figure)

{

cout << figure.GetArea() <<

"\n";

}

void main()

{

Circle circle(10);

Rectangle rectangle(10, 20);

PrintShapeArea(circle);

PrintShapeArea(rectangle);

return 0;

}

Результат:

>314>200

В данной ситуации при выборе вызываемыхметодов компилятор руководствуетсятаблицей виртуальных методов (VMT).

В этом случае происходит вызов методовклассов Circle и Rectangle, так как ониобъявлены виртуальными.

Page 14: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 14

Особенности виртуальных методов

В C++ методы, объявленные в базовом классе виртуальными,остаются виртуальными в классах-потомках.

Использовать слово virtual в классах наследниках необязательно (хотя и желательно для лучшего понимания кода).

В C++ виртуальные функции не являются виртуальными, еслиони вызваны в конструкторе или деструкторе данного класса.

Page 15: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 15

Виртуальный деструктор

Деструктор класса, имеющего наследников, всегда должен явнообъявляться виртуальным.

Это обеспечивает корректный вызов деструктора нужного классапри вызове оператора delete с указателем на базовый класс.

Деструктор, не объявленный явно виртуальным, а такжеавтоматически сгенерированный деструктор является невиртуальным.

Классы без виртуальных деструкторов не предназначены длярасширения.

Классы стандартных коллекций STL (строки, векторы) не имеютвиртуальных деструкторов, поэтому наследоваться от них нельзя.

Page 16: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 16

Абстрактные классы

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

Какова площадь объекта «Figure» и как его нарисовать?

Такие виртуальные функции следует объявлять чистовиртуальными (pure virtual), добавив инициализатор =0,опустив тело функции.

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

Экземпляр абстрактного класса создать невозможно

Page 17: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 17

Пример

class Figure

{

public:

virtual double GetArea()=0;

virtual void Draw()=0;

};

Page 18: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 18

Интерфейс

Интерфейс - абстрактный класс, содержащий только чистовиртуальные методы.

Невозможно создать экземпляр интерфейса.

Все методы интерфейса должны быть реализованы впроизводных классах.

Деструктор такого класса обязательно должен бытьвиртуальным.

Page 19: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 19

Пример

class IFigure

{

public:

virtual double GetArea()=0;

virtual void Draw()=0;

virtual void Transform()=0;

virtual void Move()=0;

};

Page 20: C++ Базовый. Занятие 11

http://www.slideshare.net/IgorShkulipa 20

Лабораторная работа №11. Полиморфизм

Написать программу с использованием наследования классов,реализующую классы:

⚫ графический объект (интерфейс)

⚫ правильный треугольник

⚫ квадрат

⚫ правильный пятиугольник

⚫ правильный N-угольник

Реализовать полиморфный метод подсчета площади.