Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Итог_Пособие C++.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.03 Mб
Скачать

3.9. Полиморфизм при наследовании классов

3.9.1 Механизмы раннего и позднего связывания

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

Мы уже говорили, что в классах-потомках можно переопределять реализацию методов родителя. Сделать это можно двумя способами:

1) Переопределение (наверное, более точным будет термин "простое переопределение")

2) Перекрытие

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

В примере 3.4 мы уже использовали такой приём, определив два разных метода show() в классах coord и point. Использовать такой способ, конечно, можно, но никаких интересных возможностей от него ожидать не приходится. Например, при выполнении примера 3.4 фрагмент кода

coord *cor = &p; // p – это переменная типа point

cor-> show();

выведет только координаты x и y – компилятор подключил метод show класса coord.

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

Для того, чтобы почувствовать разницу между простым переопределением и перекрытием, можете выполнить такой эксперимент. В программный код примера 3.4 добавьте слово virtual перед определением метода show в классе coord:

virtual void show() {тело не меняем}

Перекомпилируйте программу и убедитесь, что теперь выводятся все поля класса point – механизм позднего связывания заработал!

Отметим, что при реализации позднего связывания полезно добавить в определение соответствующего метода в классе-потомке служебное слово override (в переводе на русский - перекрытый). В нашем примере для класса coord определим метод show так:

void show() override {тело не меняем}

Такое определение заставит компилятор сделать проверку полной идентичности прототипов перекрываемых методов (без слова override компилятор в случае малейшего несовпадения прототипов будет считать их просто разными методами и не запустит механизм позднего связывания).

Кроме слова override, разрешено к использованию в этой ситуации служебное слово final, которое означает, что в следующих потомках перекрывать этот метод уже нельзя.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]