- •1. Объектно-ориентированный подход в программировании.
- •1.1 Инкапсуляция
- •1.2 Наследование
- •1.3 Полиморфизм
- •2.1 Перегружаемые (overload) функции
- •2.2 Перегружаемые (overload) операторы
- •2.3 Объектные типы данных: структуры, объединения, классы (обзор)
- •2.4. Конструкторы и деструкторы
- •2.7 Производные классы
- •2.8 Встраиваемые функции
- •2.9 Присваивание объектов
- •2.10 Передача в функции и возвращение объекта
- •2.11 Конструктор копирования
- •2.12 Указатели и ссылки на объекты
- •3.1. Модификаторы наследования
- •3.2 Конструкторы при наследовании
- •3.3 Деструкторы при наследовании
- •3.4 Совместимость типов
- •4. Виртуальные функции.
- •4.1. Раннее и позднее связывание
- •4.2 Полиморфизм и виртуальные методы
- •4.3. Использование указателей на базовые классы при адресации объектов произвольных классов.
- •4.4 Абстрактный класс
- •5. Дружественные функции.
- •5.1 “Дружественные” (friend) функции
- •6. Шаблоны функций и классов
- •6.1 Шаблоны функций
- •6.2 Шаблоны классов
4. Виртуальные функции.
4.1. Раннее и позднее связывание
Раннее или позднее связывание – это термины, относящиеся к этапу, на котором обращение к процедуре связывается с ее адресом. В случае раннего связывания адреса всех функций и процедур известны в тот момент, когда происходит компоновка программы.
Логика компилятора очень проста. Сначала он ищет метод с нужным именем, определенный внутри данного класса. Если метод с таким именем внутри класса не определен, то компилятор обращается к базовому классу и ищет этот метод там. Если найдет, то подставит в точки вызова адрес метода из родительского класса. Если не найдет, то поднимется по иерархическому дереву еще выше.
Методы, которые мы обсудили, называются статическими. Они являются статическим и в том смысле, что компилятор размещает их и разрешает ссылки на них во время компиляции. Это достаточно мощные средства для организации сложных программ. Однако они являются далеко не лучшим способом для обработки методов.
В большинстве традиционных языков программирования, включая и C, используется только раннее связывание. В противоположность этому в случае позднего связывания адрес процедуры не связывается с обращением к ней до того момента, пока обращение не произойдет фактически, то есть во время выполнения программы.
Напомним, что в языке C++ к объектам производного типа можно обращаться по указателю на базовый класс, и тогда на этапе компиляции нельзя установить, функция какого из производных классов должна быть вызвана. В ходе выполнения программы требуется проверять, на объект какого типа ссылается указатель, и только после данной проверки вызывать требуемую функцию. Эти действия и называют поздним связыванием.
Специальный механизм разрешения ссылок на методы во время выполнения программы реализован в языке C++ при помощи виртуальных методов.
Виртуальные методы являются ярким примером проявления полиморфизма. В нашем случае это способ задания одноименного действия, которое распределяется вверх и вниз по иерархии объектов, с выполнением этого действия методом, соответствующим каждому объекту в иерархии.
Различие между вызовом статического метода и вызовом виртуального метода - это различие между решением немедленным и отложенным, задержанным решением.
4.2 Полиморфизм и виртуальные методы
Виртуальные методы — один из важнейших приёмов реализации полиморфизма. Они позволяют создавать общий код, который может работать как с объектами базового класса, так и с объектами любого его класса-наследника. При этом, базовый класс определяет способ работы с объектами и любые его наследники могут предоставлять конкретную реализацию этого способа.
В объектно-ориентированных языках класс является типом данных. Полиморфизм реализуется с помощью наследования классов. Класс-потомок наследует сигнатуры методов класса-родителя, но реализация этих методов может быть другой, соответствующей специфике класса-потомка. Это называется переопределением метода. Другие функции могут работать с объектом класса-родителя, при этом вместо него во время исполнения будет подставляться один из классов-потомков. Это называется поздним связыванием.
Класс-потомок сам может быть родителем. Это позволяет строить сложные схемы наследования — древовидные или сетевидные.
Для каждого класса, имеющего хотя бы один виртуальный метод, создаётся таблица виртуальных методов. Каждый объект хранит указатель на таблицу своего класса. Для вызова виртуального метода используется такой механизм: из объекта берётся указатель на соответствующую таблицу виртуальных методов, а из неё, по фиксированному смещению, — указатель на реализацию метода, используемого для данного класса. При использовании множественного наследования или интерфейсов ситуация несколько усложняется за счёт того, что таблица виртуальных методов становится нелинейной.
