Полиморфизм Полиморфизм (polymorphism) - последний из трех "китов", на которых держится объектно-ориентированное программирование Слово это можно перевести.

Презентация:



Advertisements
Похожие презентации
Наследование Полиморфизм ВЫЗОВ КОНСТРУКТОРОВ И ДЕСТРУКТОРОВ ПРИ НАСЛЕДОВАНИИ.
Advertisements

Основы информатики Классы Заикин Олег Сергеевич zaikin.all24.org
Полиморфизм. Полиморфизм – это свойство системы использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
Объектно-ориентированное программирование С++. Лекция 6 Карпов В.Э.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Множественное наследование class A {... }; class B {... }; class C : public A, protected B {... }; !!! Спецификатор доступа распространяется только на.
Наследование и полиморфизм. «Быть» или «Иметь» а так же «Точно» или «Как получится»
OOП Инна Исаева. Подпрограмма – это большая программа, разделённая на меньшие части. В программе одна из подпрограмм является главной. Её задача состоит.
Д.з Язык С++ - занятие 31. Задача 1: 1/1 + 1/3 + 1/5 … #include using namespace std; int main() { int n; cin >> n; double sum = 0;// Сумма for.
Инструкции C++ Условная инструкция Формат: if (условие) оператор; else оператор; Пример: if (i!=0) { if (j) j++; if(k) k++; else if(p) k--; } else i--;
Лекция 10 ОбъектыЛекция 10 ОбъектыООП Инкапсуляция Возможность совместного хранения данных и кода для их обработки Наследование Возможность расширять существующие.
М.Ю. Харламов, ВНУ им. В.Даля, Семантический анализатор Семантический анализатор выполняет следующие основные действия: проверку соблюдения во входной.
Лекция 8. Введение в ООП. Часть 1 Красс Александр СПбГУ ИТМО, 2008.
Кафедра ОСУ, Java 2004 Слайд 1 Наследование Наследование позволяет использовать существующий класс для определения новых классов, т.е. способствует.
1 ©Павловская Т.А. (СПбГУ ИТМО) Курс «С#. Программирование на языке высокого уровня» Павловская Т.А.
Обработка исключительных ситуаций Исключительная ситуация (исключение) – это ошибка, возникающая во время выполнения программы. Например, ошибка работы.
Статические поля класса Статические поля хранят данные, общие для всех элементов класса. Статическое поле существует в единственном экземпляре для всех.
Процедуры и функции. Разработал учитель информатики МБОУ СОШ 50 г. Краснодара Ракута Елизавета Григорьевна « Учиться и, когда придет время, прикладывать.
Транксрипт:

Полиморфизм Полиморфизм (polymorphism) - последний из трех "китов", на которых держится объектно-ориентированное программирование Слово это можно перевести с греческого как "многоформенность Применительно с С++ этот термин обычно трактуют как способность объекта отреагировать на некоторый запрос (т.е. вызвать функцию-член) сообразно своему типу, даже если на стадии компиляции тип объекта, к которому направлен запрос, еще неизвестен В С++ полиморфизм реализуется при помощи механизмов виртуальных функций членов

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

Eсли используется класс, у которого есть производные и базовые классы, имеющие функции с одним именем и одинаковым набором аргументов, компилятор не в состоянии определить, к какому конкретно классу относится указываемый объект и какую функцию для него вызывать class Base { void f(); }; class Deriv1: public Base { void f(); }; class Deriv2: public Base { void f(); }; class Deriv3: public Deriv2 { void f(); }; // Base *b_ptr[3]; *b_ptr[0]=new Deriv1; *b_ptr[1]=new Deriv2; *b_ptr[2]=new Deriv3; //... for (int count=0; count f(); // для всех объектов будет вызвана Base::f()

Термин позднее связывание (late binding) значит, что компилятор не может определить заранее, какая функция должна вызываться на самом деле, если обращение к виртуальной функции использует указатель или ссылку на базовый класс Хотя переменная и определяется как указатель на базовый класс, она в действительности может указывать на объект производного класса Эта особенность виртуального механизма приводит к тому, что адрес функции может быть найден только во время исполнения программы При вызове функции-члена при помощи указателя необходимо решить проблему распознавания класса, к которому принадлежит указываемый объект, для того что бы функция корректно выполнилась

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

enum CLASS_ID {ID_base, ID_deriv1, ID_deriv2}; class Base { protected: CLACC_ID class_ID; public: Base() { class_ID=ID_base; /*... */ } void f(); }; class Deriv1: public Base { //... Deriv1(){ class_ID=ID_deriv1; /*... */ } friend void Base::f(); }; class Deriv2: public Base { //... int some_member; Deriv2() { class_ID=ID_deriv2; /*... */ } friend void Base::f(); };

void Base::f() { switch (class_ID) { case ID_Base: // Операторы break; case ID_Deriv1: // break; case ID_Deriv2: // break; default: // Обработка неизвестного номера класса } Программа весьма запутанна Если программист пожелает добавить новый класс, придется модифицировать исходный текст f() функции-члена класса Base

Третье: использование виртуальных функций - фактически перекладывает на компилятор все заботы о помещении в класс поля типа, генерации кода для его проверки (во время выполнения программы!) и вызова функции-члена, соответствующей реальному типу объекта Ключевое слово virtual предписывает компилятору генерировать некоторую дополнительную информацию о функции Если в некотором классе имеется функция, описанная как virtual, то в такой класс компилятором добавляется скрытый член - указатель на таблицу виртуальных функций, а также генерируется специальный код, позволяющий осуществить выбор виртуальной функции во время работы программы Конечно, использование виртуальных функций снижает быстродействие программы и увеличивает размер

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

// Базовый класс с виртуальной и не виртуальной функцией class Base { public: virtual void virt() { printf("Hello from Base::virt\n");} void nonVirt() { printf("Hello from Base::nonVirt\n");} }; // Производный класс заменяет обе функции class Derived : public Base { public: void virt() { printf("Hello from Derived::virt\n");} void nonVirt() { printf("Hello from Derived::nonVirt\n");} };

int main(void) { Base *bp = new Derived;// базовый указатель // реально ссылающийся // на производный объект bp->virt(); bp->nonVirt(); return 0; } Результат: Hello from Derived::virt Hello from Base::nonVirt

Для виртуальных функций существуют следующие правила: виртуальную функцию нельзя объявить как static спецификатор virtual необязателен при переопределении функции в производном классе виртуальная функция должна быть определена, либо должна описываться как чистая Обойти виртуальный механизм можно так bp->Base::virt(); Hello from Base::virt

В базовых классах необходимо использовать виртуальные деструкторы. Рассмотрим ситуацию: class Base { public: ~Base() { // Освобождение ресурсов } }; class Derived : public Base { public: ~Derived() { // Освобождение ресурсов } }; int main(void) { Base *bp = new Derived; // delete bp; }

Так как деструктор не является виртуальным, delete вызовет только Base::~Base, что может привести к потере ресурсов Derived Чтобы использовать механизм виртуальных функций, вы должны применять указатели или ссылки